There are at least following reasons for this:
ioctl name, looks like the speed is only guaranteed not to be greater than the value requested.
Due to some confusings in the Broadcom datasheets, the older SPI driver
spi-bcm2708 calculated the clock multiplier to be power of two instead of multiply of two. So the range of possible values was strongly reduced. This should be ok in the current driver
spi-bcm2835. Check the current module loaded via
Not sure why, but the SPI clock depends on the CPU clock. At least on my raspbian system, using the
spi-bcm2835 driver, the real clock frequency meets the expectations on full speed only (1GHz). At the default idle speed (700MHz) the SPI clock is lower (e.g. 12.5MHz real for 20MHz request). Check/change the current CPU speed settings:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor #current policy
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor #max performance
cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq #min CPU clock frequency
cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq #current CPU clock frequency
cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq #max CPU clock frequency
After some more research, regarding the overclocking, following parameters in
/boot/config.txt affect the SPI clock. Using the values provided the real timing meets the expectations.
arm_freq_min=700 #effectively disable scaling
core_freq=200 #not sure about exact meaning, but this allows precise SPI clock setup
There is a tool able to determine either configured or real clock values of the overclocking parameters:
vcgencmd get_config arm_freq
vcgencmd get_config core_freq
vcgencmd measure_clock arm
vcgencmd measure_clock core
So the overclocked system in full performance mode (correct SPI setting) is 1000(arm)/400(core)MHz.
Nice summary for raspberry pi config options