1 2 Previous Next 19 Replies Latest reply on Oct 23, 2014 11:19 AM by mikemoy

    mraa_spi_bit_per_word Problem

    mikemoy

      I am trying to write 16 bits using SPI.

      I have set: mraa_spi_bit_per_word(spi,16);

      Am I doing something wrong ?

       

      On the scope it is only doing 8-bit, then i tried different numbers for mraa_spi_bit_per_word all resulting in only 8-bits it never changed no matter what i used.

       

       

      I have the following

       

      mraa_spi_context spi;

      mraa_init();

      spi = mraa_spi_init(0);

      mraa_spi_mode(spi,MRAA_SPI_MODE0);

      mraa_spi_bit_per_word(spi,16);

      mraa_spi_frequency(spi,100000);

       

      unsigned char data[5];

        data[0] = address;

        data[1] = reg;

        data[2] = port_a;

        data[3] = port_b;

        mraa_spi_write_buf(spi, data, 4);

        • 1. Re: mraa_spi_bit_per_word Problem
          faceplant

          Shouldn't sending two 8-bit words (two bytes) be the same as sending a 16-bit word?

          • 2. Re: mraa_spi_bit_per_word Problem
            mikemoy

            No. The difference is that when sending 16-bit, your CS line is low for the entire 16bit transaction.

            • 3. Re: mraa_spi_bit_per_word Problem
              faceplant

              If your code it looks like you're sending 4 bytes (32 bits).  I assume the CS line should remain low for all 4 bytes.

               

              Are you saying that you need to send 16 bits for each byte?  I.e. does your device expect 16 bits for each of address, reg, port_a, and port_b?  If so, you should probably make your array 8 bytes and pad with zeros between each element:

               

              data[0] = 0;

              data[1] = address;

              data[2] = 0;

              data[3] = red;

              ...

               

              Note, the padding might need to be reversed if the device expects little-endian byte order.

              • 4. Re: mraa_spi_bit_per_word Problem
                mikemoy

                I need to send 16 bits per CS.

                The function calls only take a byte, so it is unclear how they would accept a word, instead of a byte.

                I am assuming that if you give it 4 bytes it will use the first 2 bytes and then send out a word, and the last 2 bytes to send out the second word.

                • 5. Re: mraa_spi_bit_per_word Problem
                  faceplant

                  I don't know for sure, but I have to assume that mraa_spi_write_buf would only toggle the CS line once.  There has to be a function that sends multiple bytes between toggling the CS line.

                   

                  Given your requirement, I think your code should look something like:


                  data[0] = 0;

                  data[1] = address;

                  mraa_spi_write_buf(spi, data, 2);

                  data[0] = 0;

                  data[1] = reg;

                  mraa_spi_write_buf(spi, data, 2);


                  • 6. Re: mraa_spi_bit_per_word Problem
                    mikemoy

                    The last parameter tells it how many bytes to send.

                    So even if you change it from 4 to 2 it will still toggle the CS line 2 times now instead of 4 .

                    • 7. Re: mraa_spi_bit_per_word Problem
                      faceplant

                      You can send as many bytes/bits as you want over SPI without toggeling the CS line.  Toggling the CS line indicates the start/end of a transfer, and that transfer can be as many bits as you want.  I have to assume that the mraa_spi_write_buf call only changes the CS line before he first byte and after the last byte.


                      • 8. Re: mraa_spi_bit_per_word Problem
                        mikemoy

                        faceplant wrote:

                         

                        You can send as many bytes/bits as you want over SPI without toggeling the CS line.  Toggling the CS line indicates the start/end of a transfer, and that transfer can be as many bits as you want.  I have to assume that the mraa_spi_write_buf call only changes the CS line before he first byte and after the last byte.


                        mraa_spi_write_buf call does toggle the CS line before and after the last byte. which is why when you set mraa_spi_bit_per_word(spi,16); it should toggle it low, then shoot out 16 bits then toggle high again. Its is not doing this.

                        • 9. Re: mraa_spi_bit_per_word Problem
                          mikemoy

                          Is there a resolution to this problem ?

                          • 10. Re: mraa_spi_bit_per_word Problem
                            KurtE

                            I may be missing something, but when I was migrating the Adafruit_ILI9341 (2.8" SPI TFT Didsplay) library over to the Edison, it appears to me that I am in full control of the SPI as well as the DC line.  This is different than the version we did for the Teensy 3.1, which used the hardware SPI 4 command queue where each queue item could be for 8 or 16 bits and it could control the CS and DC pins. 

                             

                            Again I may be missing something as the Edison docs mentioned something about 2 hardware CS pins, but I saw nothing in the docs that showed me how to use them...

                             

                            So in my fork of the Adafruit_ILI9341 driver (https://www.github.com/kurte/Adafruit_ILI9341) , I control both those pins directly.  The original library had helper functions to send out a command and data byte and those helpers toggled the CS line around each byte.  So I added helper functions like what was done for the Teensy that left the CS selected.

                             

                            Note: performance wise, every time you use something mraa_spi_transfer_buf instead of multiple mrass_spi_write calls, helps to speed things up.

                             

                            Kurt

                            • 11. Re: mraa_spi_bit_per_word Problem
                              mikemoy

                              I have a 7" lcd wired to the Edison. I am manually toggling the CS & DC lines. Since mraa_spi_bit_per_word does not work it only sends out 8-bit per write regardless if you use mraa_spi_transfer_buf or mrass_spi_write. This causes a delay from when i yank the CS line low to when the data gets spit out, then another delay in-between bytes, then again from the last byte to when i pull the CS line high.  For a LCD of this size, when you start to write allot of data these small delays add up quickly. using mraa_spi_frequency(spi,300000); i cannot use any freq faster because even though the data timing is much faster the delay from CS going low to the data just gets larger and larger as i change the speed faster and faster, thus its accomplishing nothing.

                              This is why i need the mraa_spi_bit_per_word to work so it will toggle the CS line faster than i can manually.

                              • 12. Re: mraa_spi_bit_per_word Problem
                                KurtE

                                Warning: I only know enough here to be dangerous

                                 

                                Is there a document/thread some place that tells the SPI capabilities of this SPI?  So far I have not seen it,   Like how do you enable the hardware to handle the CS pin?  My guess is that you have to set up the IO pin properly and set the mux to mode1? 

                                 

                                Is there anything talking about what the mraa_spi_bit_per_word does?  Is 16 valid or is it only something like 8 and 9?   As for having the hardware control when to and when not to control the CS pin, I am not sure the word size is the complete deciding factor. Example with the ILI9341 display, when you ask the display to give you pixel information, you need to keep the CS pin selected during the entire transfer to let the device know you want more, which could be 100s of bytes or more...

                                 

                                Again I don't have know enough about the SPI on the Edison, but with the Teensy 3.1, the SPI has something like 4 CS pins you can use.  Actually more than that as many of these CS pins can be mapped to multiple pins.  With the ILI9341 driver for the Teensy 3/3.1 (PaulStoffregen/ILI9341_t3 · GitHub) I know that Paul with a little help from me, really sped up the display by taking advantage of the hardware, which this spi has a 4 command queue, with each queue entry can transfer either 8 or 16 bits and controls which of the CS pins should be changed before and after (can be any or all of the 4 pins).  This driver uses it to control both the CS and the DC pins and is very fast.

                                 

                                I know that I have gotten  some speed up using mraa_spi_transfer_buf which is why I added it.  Before there was the write buf which returned a memory for what was read, which you had to free and with transfer you can pass in NULL pointer for read pointer if you are only doing output, which speeds things up as the system no longer has to copy the data to your buffer...   Also while I was modifying my fork of the Adafruit_ILI9341 driver (up on github),  I found the driver was always calling it's helper functions (writecommand and writedata), for each byte and these functions always logically set and clear the CS.  So in my version, I have other helpers, like writedata_cont which does not logically clear the CS.  There are other functions I added to write 16 bits, multiple 16 bits and the like.   These helped speed this version up.  I also then changed the code that set and cleared the CS and DC to be inline methods of the class which for the Edison, keeps a logical state and only if it is not in that state does it do a digitalWrite (which these also have to transition from user mode.  This helped some as well.  Note: I have versions of this code for both running as part of Arduino setup and also using MRAA as part of linux code base.  I should mentioned my version of the code for the TFT display is still really slow, but is probably sufficient for what I want it for, which is to maybe display a few buttons to control my robot and a status area, that may display things like voltage level, messages...   My guess is to get something approaching the speed of what is on the Teensy, would require having the display run as a kernel driver and not code running at user level.  For example I believe that is what Adafruit did for the RPI  with this(PiTFT - Assembled 320x240 2.8 TFT+Touchscreen for Raspberry Pi ID: 1601 - $34.95 : Adafruit Industries, Unique & fun DIY…)  version of the 2.8" display.

                                 

                                However I am not an SPI expert.  I really only started playing some with SPI when I started doing stuff with the Teensy and mainly only with the Adafruit displays.  I did have to stumble along some to figure out some issues with the display when it would not work when you were also using the microSD card or the Touch capabilities of the Adafruit 2.8" TFT shield.  I personally have only scratched the surface of SPI.  For example there are several CPUs (including teensy) that have multiple ways to transfer data to SPI including DMA.  For example I have seen a version of the library that started with Adafruits code the Teensy code, plus... and created ILI9341_due which is specific to the Arduino DUE and uses DMA to do the transfers, which again speed things up.

                                 

                                So again I wonder if there is any document that describes the SPI capabilities of the Edison?  Is there a hardware fifo queue like Teensy? Does it support DMA?  what type of hardware control do I have for CS pins?  

                                 

                                Sorry that dribbled on here.

                                • 13. Re: mraa_spi_bit_per_word Problem
                                  mikemoy

                                  FYI, I am not using the Arduino kit i am using the Edison Mini kit. I am using a level shifter from it to my LCD.

                                  I have had this same LCD wired up to the RPI B+ and it worked just fine. I am sure that the Edison will give good results as well given its lower processor speed.

                                  Just need to minimize the delays in between the CS signal and data is all. Almost every product i have made uses SPI so i am well versed in it.

                                   

                                  I am not sure if mraa_spi_bit_per_word is 8 or 9 bit or does allow more like 16 & 32 bit writes (which would be awesome).

                                  I have not been able to find any documentation for the SPI registers for me to write my own. So currently i am at the mercy of mraa.

                                  • 14. Re: mraa_spi_bit_per_word Problem
                                    mhahn

                                    post.user_wrote.label:

                                     

                                    I am not sure if mraa_spi_bit_per_word is 8 or 9 bit or does allow more like 16 & 32 bit writes (which would be awesome).

                                    I have not been able to find any documentation for the SPI registers for me to write my own. So currently i am at the mercy of mraa.

                                    note: mraa is open source - if you are interested you can always look up details in the sources: intel-iot-devkit/mraa · GitHub

                                    1 2 Previous Next