many of the "portability" is created by users / programmers.
yes, peripherals vary widely and generally there is no "portability" from one family of mcu's peripherals to another family's peripherals. with that said, however, a great deal of portability can be achieved by the programmer.
Take timers for example. most of the times, they are set to run periodically. So a typical set of timer routines should allow you to set its timing (period, prescaler, source, etc.) and another set to install a user routine that you want to run periodically. that user routine can be as simple as set or clear a flag, or perform some small actions, like triggering adc, read a set of pins, etc.
If you build your user code on those sets of routines, and develop those routines for different targets, your code can port seamlessly from one family to another, without much / any changes.
kind like low-power consumption coding is more of a software issue than a hardware issue, portability is far more in the hands of the programmer than in the device manufacturers.