a trap, a fault, and an interrupt
Imagine you are reading at your desk and three different things can pull your attention to the front office. First, you deliberately ring the front-desk bell because you need help - you chose this. Second, you try to open a drawer and it is jammed, forcing you to stop and deal with the problem - this came from your own action going wrong. Third, the doorbell rings because a delivery arrived from outside - nothing to do with what you were doing. These three are the everyday shapes of a trap, a fault, and an interrupt: all three pull the CPU into the kernel, but for very different reasons.
Here is the precise distinction. A trap is synchronous and intentional: the program deliberately runs an instruction (like the syscall instruction) to ask the kernel for service. A fault is synchronous and unintentional: the CPU is executing an instruction and detects something wrong - dividing by zero, dereferencing an invalid address, hitting a page that is not in memory - and switches to the kernel to handle it; some faults are recoverable (the kernel loads the missing page and re-runs the instruction) and some are fatal (it kills the program with a segmentation fault). An interrupt is asynchronous and external: a device such as the network card, disk, keyboard, or a timer raises a signal that has nothing to do with the instruction currently running; the CPU pauses, jumps to the kernel's handler, services the device, and resumes. The dividing lines are: synchronous (caused by the current instruction) versus asynchronous (caused by an outside device), and intentional (a trap) versus unintentional (a fault). All three are collectively the kernel's entry points.
Why it matters: keeping these three straight is the key to reading how a kernel actually gets control. A system call is a trap; a segmentation fault and a page fault are faults; a key press or an arriving network packet is an interrupt. People loosely lump them as 'exceptions' or even all call them 'interrupts,' but the three differ in cause and in whether they can be retried. Knowing which is which tells you whether an event was the program's own doing, a bug, or the outside world knocking.
Calling write() is a trap - you asked. Dereferencing a NULL pointer triggers a fault - the CPU caught your bad access. A finished disk read or a pressed key raises an interrupt - the outside world arrived, unrelated to whatever instruction your program was on.
Trap = you asked; fault = your instruction went wrong; interrupt = outside arrived.
Exact terminology varies by CPU and textbook - some lump traps and faults together as 'exceptions,' and naming differs across architectures. The durable distinction to hold onto is the two axes: synchronous versus asynchronous, and intentional versus an error.