2

I am wondering if there is a user-definable, built-in ISR function in the HAL library that triggers as soon as a byte is received in the SPIx Rx buffer on STM32L4xx MCU? For instance, as a startup test, I would like to send one byte (0xBC) from a Master STM32L452 nucleo board via SPI2 to a Slave STM32L452 nucleo board. Once the Slave board receives the byte, it flashes LED2, and transmits a different byte (0xCD) back to the Master. Once the Master receives the byte, it flashes LED2 as confirmation. I have initialized both boards as Master/Slave, enabled DMA and global interrupts, 8 bits per transfer using MXcube. I can achieve what I want using the HAL_SPI_Transmit_DMA() and HAL_SPI_Receive_DMA() functions and delays written into the while(1) portion of my main routine (as below). However, I would like to achieve the same using an ISR function that automatically executes once a byte is received into the SPI Rx Buffer.

Master Code:

   uint8_t spiDataReceive = 0;
   uint8_t spiDataTransmit = 0xBC;

   while(1) {
       if(!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)) {
             //Transmit byte 0xBC to Slave and Receive Response
             HAL_SPI_Transmit_DMA(&hspi2, &spiDataTransmit, 1);
             HAL_Delay(20);
             HAL_SPI_Receive_DMA(&hspi2, &spiDataReceive, 1);

             if(spiDataReceive == 0xCD) {
                 flashLED2();
                 spiDataReceive = 0x00;
             }
        }
   }

Slave Code:

 uint8_t spiDataReceive = 0;
 uint8_t spiDataTransmit = 0xCD;

 while(1) {
      HAL_SPI_Receive_DMA(&hspi2, &spiDataReceive, 1);
      HAL_Delay(10);

      if(spiDataReceive == 0xBC) {
         HAL_SPI_Transmit_DMA(&hspi2, &spiDataTransmit, 1);
         flashLED2();
         spiDataReceive = 0x00;
      }
 }
dm123
  • 21
  • 1
  • 1
    DMA is not supposed to be used if you want to receive 1 byte. – 0___________ Apr 21 '20 at 19:17
  • @P__J__ - I agree. But... - let's assume that DMA is already used to transfer more than one byte in the desired application, and the OP started testing the setup with a single byte for simplicity. This would justify using an unnecessary DMA here... – HelpingHand Apr 25 '20 at 13:07

2 Answers2

1

No library is needed. You need to set RNEIE bit in the SPI CR register and enable in the NVIC the interrupt. 2 lines of code. No libraries needed.

The only needed resource is the Reference Manual from the STM website.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Hi, could you be more specific? How do I access the SPI CR register and the NVIC was enabled with MXcube. Also, where do I write my interrupt service routine? – dm123 Apr 21 '20 at 20:06
  • @dm123 this is the main problem with HAL and arduino. People think that they can program uCs without knowing their platforms and toolchains. – 0___________ Apr 21 '20 at 20:16
1

Yes, the HAL provides user callbacks. In order to use those, you have to activate the corresponding interrupt in NVIC and have the HAL handler called by the interrupt vector table (please have a look at stm32l4xx_it.c, too).

But before you do so, you should consider the following questions:

  • If you feel confused or frustrated by the complexity of ST HAL libraries, read the Reference Manual and follow the advice of P__J__ (see other answer). If you feel confused or frustrated by the complexity of the hardware interface, follow the present answer.

  • Both HAL_SPI_Transmit_DMA() and HAL_SPI_Transmit_IT() support a variable number of transfer bytes. If all you are going to need is that one-byte transfer, HAL functions may be an overkill. Their advantage is that you can run some C library functions without dealing with HW register access in C (if that is quite new to you, coming from the arduino ecosystem). And of course, to transfer more than a single byte through the same interface when you extend your application.

  • You should decide whether you want to get an interrupt from the DMA you have tied to the UART, or if you want to avoid the DMA and get the interrupt from the UART itself. From my point of view, you should really not trigger an ISR by the same interrupt event which is used to start a DMA transfer to fetch the data!

  • In the same way as you find a description of the HW registers in the Reference Manual and Data Sheet of the controller, you find documentation on the HAL (layering concept, usage requirements etc.) in the User manual of STM32L4/L4+ HAL and low-layer drivers (see sections 70 and 102, resp., and chapter 3). Of course, this interface aims mostly for abstraction and portability whereas directly addressing the HW interface usually allows much better efficiency in terms of latency/CPU load, and ROM/RAM usage. The "Low-Level" library drivers aim for a certain compromise, but if you are new to this whole topic and unsure what to start with, you should either start from the HW register interface, or from the portable HAL library API.

  • If the specification documents (HW or Lib description) are too abstract for you and you prefer some hands-on information source, you may want to first have a look at STM32Cube firmware examples for STM32CubeL4. These also include SPI data exchange use cases (SPI_FullDuplex_ComIT for example) that are available for NUCLEO-L4532RE (and others) and described in application note AN4726 (page 16).


In addition to the interrupt selection/handling, you should check two more aspects of your program:

  • If you get an interrupt from the hardware, there is no reason for the HAL_Delay() calls.

  • Keep in mind that on SPI, you can only "return" data from slave to master while the master is transferring data (which may be zero data). Otherwise, the "transmit" call on the slave side will only put data into the TX register, and the SPI peripheral will wait infinitely for the SCK trigger from the master...

HelpingHand
  • 1,294
  • 11
  • 27