Subsystems are just a convention used to provide several implementations of a peripheral (like microcontroller peripherals, an external imu board...), protocol (gps, communications...) or algorithm (control, estimation...). Function calls are written "by hand" and the build system takes care to compile the particular implementation.
They are selected and configured with a
<subsystem name="foo" type="bar"> in the firmware section of the airframe file. All this does is basically include a makefile foo_bar.makefile that adds the respective sources and adds a few configuration options. (See conf/autopilot/subsystems/...)
This makes it easier to put an airframe file together (they replace the old raw makefile section) and also allows us to change the code and move/rename files behind the scenes without breaking everyones airframe files.
Modules use code generation in order to allow people to use them by only editing the vehicle's xml configuration as opposed to changing/adding to the code of the autopilot. Typically, function calls are generated for initialisation and in the mainloop for timers (periodic in paparazzi slang) and events. The event and periodic functions of the Modules get called at the end of event_task_ap and periodic_task_ap respectively.
So the difference is that with subsystems you explicitly call the functions (e.g. control loops) from the main ap loop, whereas the event/periodic functions of the Modules get called at the end of the main event/periodic tasks. So Modules are perfect to add stuff like extra payload and sensors, but Subsystems give you tighter control over when and in what order to call functions (e.g. for estimation/control).
Modules naturally provide the "several implementations" feature of the Subsystems. So, we could have a "generic" main.c consisting only in calls to the generated functions. Nevertheless, care should be taken that switching to a "module only" configuration doesn't become detrimental to the readability and debugability of the code.
You can also wrap some subsystem code as a modules (e.g. infrared), or the other way round (e.g. imu_ppzuav). As you can see with the imu_ppzuav module it also still expects a direct ImuEvent call from main_ap, so you could say it's not a "pure" module.