Page 1 of 1

STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 2:18 am
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");


Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 4:27 am
by rocky
I believe you need to use the cycle of spiStart/Select/Send/Unselect for each transfer.

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 9:05 am
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

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 8:15 pm
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.

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 8:43 pm
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

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 9:12 pm
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.

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 9:27 pm
by Giovanni
Hi,

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

Giovanni

Re: STM32L: SPI+DMA question

Posted: Thu Feb 06, 2014 11:48 pm
by yushanh
Found it! Thanks a lot! :D