## SPI has more speeds

7 posts
The SPI Controller driver spi_bcm2708 support speeds in doubles from ~8kHz to ~125MHz. This leaves large gaps, escpecially at the higher speeds (8, 16, 32, 64MHz).
Removing this constraint in the driver, gives at least 32000 speeds to choose from. I haven't tried them all, but these are my findings.

Using the Bus Pirate I have measured some low speeds

This table shows which speed was asked for, what divisor was used, the resulting theoretical speed and the measured speed.
Code: Select all
` asked     cdiv       given      measured-----------------------------------------    4000     62500      4000         4760   5000     50000      5000         5940   6000     41667      5999         7130   7000     35715      6999         8310   8000     31250      8000         9510   9000     27778      8999        10700  10000     25000     10000        11880  80000      3125     80000        94590 100000      2500    100000       118640`

The Bus Pirate is too slow for high speeds, so I have used the sainsmart18fb FBTFT driver to measure the time it takes to update the display at different speeds.

This table shows which speed was asked for, the resulting theoretical speed and the measured frames per second.
Code: Select all
` asked    given    fps-----------------------  12       11.9     31  16       15.6     38  20       19.2     48  24       22.7     59  32       31.2     65`
So it certainly looks like it's working.

Techincal information
The datasheet has this to say about the CDIV (Clock Divider) field of the CLK register (page 156):
SCLK = Core Clock / CDIV
If CDIV is set to 0, the divisor is 65536. The divisor must be a power of 2. Odd numbers rounded down. The maximum SPI clock rate is of the APB clock.

This is the codesnippet from the driver that sets the divisor.
From bcm2708_setup_state()
Code: Select all
`   bus_hz = clk_get_rate(bs->clk);   if (hz >= bus_hz) {      cdiv = 2; /* bus_hz / 2 is as fast as we can go */   } else if (hz) {      cdiv = DIV_ROUND_UP(bus_hz, hz);      /* CDIV must be a power of 2, so round up */      cdiv = roundup_pow_of_two(cdiv);      if (cdiv > 65536) {         dev_dbg(dev,            "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",            hz, cdiv, bus_hz / 65536);         return -EINVAL;      } else if (cdiv == 65536) {         cdiv = 0;      } else if (cdiv == 1) {         cdiv = 2; /* 1 gets rounded down to 0; == 65536 */      }   } else {      cdiv = 0;   }`
By default bus_hz = 250MHz which is the Core clock.

What I have done, is to remove the roundup_pow_of_two() statement.
I don't know if this has some unknown side effects, but I was hoping that someone could help test this more thoroughly.
For instance I don't have any equipment to test SPI reading.

Code: Select all
`uname -aLinux raspberrypi 3.6.11+ #371 PREEMPT Thu Feb 7 16:31:35 GMT 2013 armv6l GNU/Linuxsudo rmmod spi_bcm2708wget http://tronnes.org/downloads/2013-05-10-no-power-of-two-spi-bcm2708.zipunzip 2013-05-10-no-power-of-two-spi-bcm2708.zipdmesg -Csudo insmod spi-bcm2708.kodmesgbcm2708_spi bcm2708_spi.0: master is unqueued, this is deprecatedspi spi0.0: setup: want 500000 Hz; bus_hz=250000000 / cdiv=500 == 500000 Hz; mode 0: cs 0x00000000spi spi0.0: setup: cd 0: 500000 Hz, bpw 8, mode 0x0 -> CS=00000000 CDIV=01f4spi spi0.1: setup: want 500000 Hz; bus_hz=250000000 / cdiv=500 == 500000 Hz; mode 0: cs 0x00000001spi spi0.1: setup: cd 1: 500000 Hz, bpw 8, mode 0x0 -> CS=00000001 CDIV=01f4bcm2708_spi bcm2708_spi.0: SPI Controller at 0x20204000 (irq 80)# I used this to test different speeds with the Bus Piratewget https://raw.github.com/torvalds/linux/master/Documentation/spi/spidev_test.cgcc -o spidev_test spidev_test.csudo ./spidev_test -D /dev/spidev0.0 -s 80000dmesgspidev spi0.0: setup: want 80000 Hz; bus_hz=250000000 / cdiv=3125 == 80000 Hz; mode 0: cs 0x00000000spidev spi0.0: setup: cd 0: 80000 Hz, bpw 8, mode 0x0 -> CS=00000000 CDIV=0c35spidev spi0.0: setup: want 80000 Hz; bus_hz=250000000 / cdiv=3125 == 80000 Hz; mode 0: cs 0x00000000`

References
* Datasheet: http://www.raspberrypi.org/wp-content/u ... herals.pdf
* SPI driver source: https://github.com/raspberrypi/linux/bl ... -bcm2708.c
* Bus Pirate: http://dangerousprototypes.com/docs/Bus_Pirate
* Bus Pirate Logic Analyzer mode: http://dangerousprototypes.com/docs/Logic_analyzer_mode
Posts: 510
Joined: Tue Oct 16, 2012 6:21 pm
Location: Norway
Just tried this. It is working fine!

Thanks for sharing the code and knowledge.
Posts: 2
Joined: Tue May 21, 2013 8:40 am
2 Questions:

When I reboot the Raspi, the update for the SPI speed is not active anymore. How do I have to install it, so it stays active after a reboot?

Just for curiosity. Why has the orginal limitation on different SPI speeds been put into the system? Are there any problems to be expected with other SPI speeds?
Posts: 2
Joined: Tue May 21, 2013 8:40 am
swisslizard wrote:When I reboot the Raspi, the update for the SPI speed is not active anymore. How do I have to install it, so it stays active after a reboot?
Replace this file: /lib/modules/3.6.11+/kernel/drivers/spi/spi-bcm2708.ko

swisslizard wrote:Why has the orginal limitation on different SPI speeds been put into the system?
I don't know.

swisslizard wrote:Are there any problems to be expected with other SPI speeds?
I don't know. If not someone with access to the full datasheet can shed some light on this, testing is the only way.

I have put together a page with the knowledge I have aquired: http://elinux.org/index.php?title=RPi_SPI
Posts: 510
Joined: Tue Oct 16, 2012 6:21 pm
Location: Norway
Hello,

I'm a complete newbie to SPI, but I was trying to learn a bit. I have a TFT display that does support SPI (ILI9430 chip) and I was trying to have my PI interface with it. However, I ran into issues and from googling and asking others for help, it might be due to a 9-bits per word on this chip, but I'm not sure. I've tried using 8-bit and 9-bit with spidev, but I was never able to successfully communicate with the TFT display.

I saw a post here http://lallafa.de/blog/2013/03/watterott-mi0283qt-9a-display-for-the-rasbperry-pi/ which does mention that it might be 9-bit, an this person used notro's driver framework to get his working. I tried looking at the code and since i'm new to embedded coding, didn't get it to work on my box.

Essentially here is the code i tried:
Code: Select all
`void SPI::test(unsigned short *data){   struct spi_ioc_transfer spi;   spi.tx_buf = (unsigned long)&data;   spi.rx_buf = (unsigned long)NULL;   spi.len = 2;   spi.delay_usecs = 0;   spi.speed_hz = 1000000;   spi.bits_per_word = 9;   int ret = ioctl(this->spifd, SPI_IOC_MESSAGE(1), &spi);   if (ret < 0)   {      perror("Problem transmitting spi data...ioctl");      exit(1);   }}`

I never got an error about SPI communication, but then again my display didn't do what I expected it to. According to Adafruit support, I am to set the D/C pin to LOW before I write the command to the SPI bus. However, they also told me that the bits_per_word should be 8 so I'm not quite sure what to believe.

Code: Select all
`void TFT_ILI9340::writeCommand(unsigned short cmd){   digitalWrite(dcPin_, LOW);   spi_->spiWriteRead(&cmd, 1);   digitalWrite(dcPin_, HIGH);}`

My main
Code: Select all
`int main (){    TFT_ILI9340 tft(const_cast<char*>("/dev/spidev0.0"), 7);    cout << "tft test program" << endl;    tft.writeCommand(0x28);  // turn display off    return 0;}`

can anyone please offer some advice to what i am doing incorrectly? i have made sure spidev is enabled on the PI and it has rw permission. Does spidev support 9 bits_per_word out of the box?

Here is what i'm running (uname -a)
Code: Select all
`Linux raspberrypi 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l GNU/Linux`

Posts: 20
Joined: Mon Jun 03, 2013 12:55 am
* ILI9340 (datasheet) controller with built in pixel-addressable video RAM buffer
* 4 wire SPI digital interface - this display talks in '8-bit' SPI check the Arduino library source for how to communicate

The Watterott display, uses an ILI9341, which is a different controller.

Many display controllers can do both 8 and 9-bit SPI. With 9-bit SPI the D/C signal is embedded as the 9nth bit. Most often the display breakout board hardwire this interface choice.
D/C specifies whether the SPI data sent is Data (D/C=1) or Command (D/C=0). In the datasheet, this is shown in the D/CX column in the Command list.

When I made my first framebuffer driver for the previous Adafruit 2.2" display, I first drove it from userspace using info from the Arduino example.

FYI: I just received that same display, and will hopefully add FBTFT support for it in the coming months.
Posts: 510
Joined: Tue Oct 16, 2012 6:21 pm
Location: Norway
@notro - thank you for your reply. I did try using 8-bit first and that didn't work for me. clearly, i must be doing something wrong, but I can't figure out what. After you get it working and integrated into your framework, do you think you can show me an example of a simple userspace program to drive it? Looking at the arduino code, it's mostly avr-gcc which i'm not familiar with but have been reading about to try to get that port to the PI working.

thanks again!
mike

Posts: 20
Joined: Mon Jun 03, 2013 12:55 am