4 years, 7 months ago.

SPI 16-bit write not working starting from mbed libs rev.128?

Hi,

I have a problem with my very simple program for Nucleo with STM32L053R8 uC, where SPI is configured for 16 bits, mode 0, since the device natively accepts 16-bit commands.

Up to mbed libs rev.127 it worked flawlessly with old-fashioned, synchronous 16-bit write like "SPIdeviceObject.write(0x0c01);", where 0x0c was shifted out first, then 0x01, but starting from mbed libs rev.128 I need to split it into two 8-bit wide transactions.

Is this an intentional behavior that 16-bit transfers in a single write are not allowed any more? If yes, is it documented anywhere?

1 Answer

4 years, 7 months ago.

Hi Tomasz, I just browsed the mbed SPI layer and the STM L0 MCU on rev 137 and I cannot see that there is a 16bit SPI problem. Why not to switch to the latest mbed and try it again.

Of great help is also the offline compiler using an mbed5 SPI sample this allows to step into the mbed SPI and the STM HAL code. This helps me a lot.

Regards Helmut

The story behind it: the problem arose when I updated mbed libs from rev. 92 to the newest 137. After that It didn't work as expected. Then I did a bisect to find the exact revision, which introduced this IMO regression. It was rev.128. I also had a short peek at the changes between revs 127 and 128 and there were several SPI-related ones, including "global introduction of SPI async". Then I had to go away. When I get back home on Tuesday, I can produce a piece of code showing the flaw and also get some dumps from logic analyzer, if you are interested. I can also try it on another Nucleo board - F401RE. To me it seems to be a more general problem.

posted by Tomasz Guszkowski 12 Mar 2017

Hi,

I have just checked it with logic analyzer with three different Nucleo boards: L053R0, F103RB and F401RE. In all three cases it works OK with mbed libs rev.92-127, with mbed libs rev.128 and up, including the newest 137, it adds additonal 16 clock cycles and effectively shifts another 0x0000 value, what is not what I expect. In other words it writes 32 bits instead of 16, where the most significant half is what it should be, the least significant part is 16 cleared bits. The program is extremely simple:

#include "mbed.h"
 
SPI device(SPI_MOSI, SPI_MISO, SPI_SCK);
DigitalOut ChipSelect(D7);
 
int main() {
    device.format(16, 0);
    for(;;) {
        wait_us(20);
        ChipSelect = 0;
        device.write(0x0c01);
        ChipSelect = 1;
    }
}
 

I hope that finally, after half a year, someone will correct this, instead of constantly saying "it works" without checking it out.

BR, Tomek

/media/uploads/stellaris/ok.png /media/uploads/stellaris/notok.png

posted by Tomasz Guszkowski 14 Mar 2017

Hi Tomasz, I know that this is a little bit hacky, however maybe it is a workaround for you using the native HAL layer e.g.:

  1. if DEVICE_SPI_ASYNCH
  2. define SPI_S(obj) (( struct spi_s *)(&(obj->spi)))
  3. else
  4. define SPI_S(obj) (( struct spi_s *)(obj))
  5. endif

struct spi_s *spiobj = SPI_S(((spi_t *)( (char *)_spi+4) )); SPI_HandleTypeDef *handle = &(spiobj->handle);

HAL_StatusTypeDef err; err = HAL_SPI_TransmitReceive(handle, txbuf, rxbuf, tlen, 10);

The HAL_SPI_TransmitReceive can be copied into your project and you can modify it if needed. I use this for SPI block transfers instead of single byte transfers. Regards Helmut

posted by Helmut Tschemernjak 15 Mar 2017