STM32L: SPI+DMA question

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
yushanh
Posts: 31
Joined: Mon Jul 29, 2013 6:23 pm

STM32L: SPI+DMA question

Post by yushanh »

Hi,

I used to use the SPI (without DMA) functions from ST library directly to control my radio, but now I'd like to move to ChibiOS to do the same thing. The problem I'm facing now is that I could not get the correct part information. Basically in my code, I send a command to ask for part information, and then another command to read the response. The data field will arrive after CTS has been received. Could someone point out if I use the SPI+DMA function wrong? Thanks,

PS. I removed the serial over usb codes just for clarity.

Shan


Code: Select all


static uint8_t txbuf[64] = {0};
static uint8_t rxbuf[64] = {0};

static const SPIConfig spicfg = {
  NULL,
  GPIOB,
  12,
  SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_DFF  /* 0b0000101000010100 */
};


void checkCTS() {
  while(TRUE) {
    rxbuf[0] = 0x00;
    spiReceive(&SPID2, 1, rxbuf);
    if (rxbuf[0] != 0xff) {   
    } else {                  /* CTS received, break */
      break;
    }
  }
}

int main(void) {
  unsigned i;
  halInit();
  chSysInit();
  sduObjectInit(&SDU1);
  sduStart(&SDU1, &serusbcfg);

  palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |  PAL_STM32_OSPEED_HIGHEST);           /* NSS.     */
  palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |   PAL_STM32_OSPEED_HIGHEST);           /* SCK.     */
  palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5));              /* MISO.    */
  palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |  PAL_STM32_OSPEED_HIGHEST);           /* MOSI.    */
  palSetPad(GPIOB, 12);  /* NSS pin pull high in the start */

  while (TRUE) {
    spiAcquireBus(&SPID2);
    spiStart(&SPID2, &spicfg);

    spiSelect(&SPID2);
    txbuf[0] = PART_INFO;
    spiSend(&SPID2, 1, txbuf);
    spiUnselect(&SPID2);

    spiSelect(&SPID2);
    txbuf[0] = READ_CMD_BUFF;
    spiSend(&SPID2, 1, txbuf);
    checkCTS();
    spiReceive(&SPID2, 8, rxbuf);
    spiUnselect(&SPID2);

    for (i = 0; i < 8; i++) {
     chprintf((BaseSequentialStream *)&SDU1, "0x%02x\r\n", rxbuf[i]);
    }

    spiReleaseBus(&SPID2);
    chprintf((BaseSequentialStream *)&SDU1, "------------------------------\r\n");

rocky
Posts: 11
Joined: Thu Sep 12, 2013 4:21 am

Re: STM32L: SPI+DMA question

Post by rocky »

I believe you need to use the cycle of spiStart/Select/Send/Unselect for each transfer.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32L: SPI+DMA question

Post by Giovanni »

You don't need to do spiStart() for each transfer, you need that only one time in order to configure the SPI or if you need to re-configure the SPI using different parameters. You don't even need acquire/release unless there are multiple threads trying to use the same SPI.

About your problem, I don't know the protocol of your radio but I have a note: doing spiSend() and then spiReceive() is different from doing spiExchange().
spiSend() and then spiReceive() transmit and receive at separate times, first N frames are sent (incoming data is ignored) then N frames are received sending all ones in the meanwhile.
spiExchange() transmits and receive at the same time, one bit transmitted and one bit received for each clock pulse.

What is your scenario exactly?

Giovanni
yushanh
Posts: 31
Joined: Mon Jul 29, 2013 6:23 pm

Re: STM32L: SPI+DMA question

Post by yushanh »

Hi Giovanni,

Thanks for pointing out the difference between spiSend/spiReceive and spiExchange.

In my scenario, the master (microcontroller) should send a command to the slave device first (SDO) and then read the response from it (SDI).
The command would be one byte and the response would be similar to the following format: "CTS(1 byte), data0 (1 byte), data1, data2, data3, ... , data7".
Therefore, spiSend/spiReceive is a better selection.

I remove the spiAcquire/spiRelease code but still did not return the right data. I wonder if spiSend() send the data packet to the slave directly or if there's any time delay? And what about spiReceive()? The reason I'm asking is I'd like to make sure I start to receive packet after the transmitting process finishes completely.

Thanks,
S.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32L: SPI+DMA question

Post by Giovanni »

I would check what you specified in the SPI CR1.

SPI_CR1_MSTR, SPI_CR1_SSM - No need for those because SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI are enforced internally.

SPI_CR1_DFF - Do you need 16 bits frames? do not specify this if you need 8 bits frames.

Giovanni
yushanh
Posts: 31
Joined: Mon Jul 29, 2013 6:23 pm

Re: STM32L: SPI+DMA question

Post by yushanh »

Thanks Giovanni!

It works! I thought SPI_CR1_DFF is for 8-bit format... :/

Could you point out to me where are SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI enforced to be ON?

Thanks again!

S.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32L: SPI+DMA question

Post by Giovanni »

Hi,

Look into the spi_lld_start() function, some bits are enforced there because required by the driver.

Giovanni
yushanh
Posts: 31
Joined: Mon Jul 29, 2013 6:23 pm

Re: STM32L: SPI+DMA question

Post by yushanh »

Found it! Thanks a lot! :D
Post Reply