I am working on STM32L152VB-A controller. I am using FreeRTOS.
I used CubeMX to generate the code and I configured USART1 with global interrupts.
The non interrupt RX and TX (HAL_UART_Receive and HAL_UART_Transmit) is working.
But I am trying to make it work with interrupts.
Only after I called HAL_UART_Receive_IT, I am getting interrupt.
Since I couldn't know the receive data size, I am planning to receive characters one by one.
Since I use RTOS, I am confused about where to write HAL_UART_Receive_IT, as the message can come at any time. can anybody guide me??
PS: I tried calling the HAL_UART_Receive_IT inside ISR, but it is also not working.
I think you're confusing HAL_UART_Receive_IT with a function which actually receives anything. This is not the case. This function merely enables the UART peripheral and its receive interrupt.
If you want to stick with the HAL library you need to pass a struct of type UART_HandleTypeDef as parameter to HAL_UART_Receive_IT which contains
a uint8_t* pointer to a receive buffer
a transfer counter for the number of elements you'd like to receive
As far as I know there is no way for receiving elements indefinitely with this framework because once the transfer counter reaches zero the receive interrupt gets disabled automatically. So if you need this you're probably better of writing the ISR yourself by overwriting the weak function defined by ST (most likely called "UARTx_IRQHandler").
To finally integrate the receive interrupt in FreeRTOS you've got two options:
Receive data inside the ISR into a raw (uint8_t*) buffer like HAL does and use a critical section which temporarily disables the receive interrupt when accessing it.
Receive data inside the ISR into a FreeRTOS queue using the interrupt safe API. The official FreeRTOS book chapter 6 explains this very well.
I created the following task (consider a high priority):
void UARTReceiveTask(void const * argument)
{
/* USER CODE BEGIN UARTReceiveTask */
/* Infinite loop */
for(;;)
{
osSemaphoreWait(BinarySemaphoreUARTHandle, osWaitForever);
HAL_UART_Receive_IT(&huart3, message_received, 2);
}
/* USER CODE END UARTReceiveTask */
}
Then, if you are using HAL, you must know that HAL_UART_RxCpltCallback() is executed on the UART ISR, so I wrote:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART3){
osSemaphoreRelease(BinarySemaphoreUARTHandle);
}
}
I only followed the tips on the "Mastering the FreeRTOS" document (Chapter 6) to deferr interrupts to tasks.
I haven´t dug deep into it, but I know this info is important if you are working with FreeRTOS and Arm Cortex systems.
Hope I helped!
Related
Assume there are two boards with stm32 micro-controllers which are connected to each other with rs-485 (each board has a uart-to-rs485 transceiver). This is the connection diagram and the accessible ports:
I want to be able to re-program each board separately using rs-485 wires that are available. Using st system bootloader and boot0 pin is not an option because it requires changing the PCB and re-wiring the system.
So I need to write my own custom bootloader. What I intend to do is to separate the flash memory of the B-1 MCU into three parts:
20KB for bootloader
120KB for B-2 application (as kind of a buffer)
360KB for B-1 application (bootloader jumps to this part after finishing boot mode)
and for B-2, two partitions:
20KB for bootloader
100KB for main application
and using the UART interface of B-1, I can load the .hex files to the specified flash area and tell the MCU what to do with it (either use it as it's own main app or send it to B-2).
Here is a brief algorithm for the bootloader:
// B1: starts from bootloader
for (5 seconds) {
// check for the boot command from UART
if (command received) {
// send boot and reset command to B-2 and receive ack
// start the boot mode
while (boot mode not aborted) {
// receive command packet containing address
if (command == header && address == B1) {
// prompt for the main .hex file and store it in B-1 partition
} else if (command == header && address == B2) {
// prompt for the main .hex file and store it in B-2 partition
// send header and the app to B-2 using rs-485 port
} else if (command == abort) {
break from while loop
}
}
} else {
// do nothing
}
}
// jump to main application
Now I have 2 concerns:
Since there is no gpio connection between B-1 and B-2 to activate boot mode for B-2, is it possible for B-2 board to set a flag in flash memory outside of it's main application area to check for it and use it as a boot mode activation flag?
Is it possible to write the stream of data directly from uart input to the flash memory area of each application? like this:
// Obviously this address is outside the flash area of the current bootloader running
uint8_t appAddress = B2_APP_FLASH_MEMORY_PARTITION_START_ADDRESS;
for (i from 0 to size_of_app) {
hal_uart_receive(&uartPort, appAddress + i, 1, timeout);
}
Since there is no gpio connection between B-1 and B-2 to activate boot mode for B-2, is it possible for B-2 board to set a flag in flash memory outside of it's main application area to check for it and use it as a boot mode activation flag?
I am not sure that you are suggesting, or how your suggestion will solve the problem. Ideally you would have a means form B1 of directly resetting B2 via its /RESET line, but failing that if it is loaded with an application that accepts a reset command or signal over the RS-485, then you can then have it issue a soft-reset to start the bootloader. On Cortex-M devices you can do that through the NVIC.
If you need to communicate information to the B2 bootloader - perhaps to either invoke an update or to bypass that and boot the application, you need not program flash memory for that, you can simply write a boot command or signature via a reserved area of SRAM (best right at the top) that is not initialised by the runtime start-up (or the content of which you capture before such initialisation). Content in SRAM will survive a reset so long as power is maintained, so it can be used to communicate between the application and the bootloader - both ways.
This is of course a bootstrap issue - what if there is no application loaded to accept a reset command, or the application is not valid/complete (programming interruption). Well the relocated application area will have its vector table including its initial-SP and reset vector right at the start. In your bootloader when the first 8 bytes of the image are received, you hold them back and do not program that area until the rest of the image is written. By programming the reset vector last, if the programming is interrupted, that location will not be a valid address. The bootloader can validate it (or check if it is in the erase state) and if not valid/written, it can wait indefinitely for an update or simply reset to repeat the update polling. Be aware of a bit of an STM32 gotcha here though - most parts erase flash to "all-ones" (0xFF) state, some however (STM32Lxx parts) erase to "all-zeroes". Of course you couls simply check for 0x00000000 or 0xffffffff since neither would be a valid start address, or explicitly check the range.
Is it possible to write the stream of data directly from uart input to the flash memory area of each application? like this:
Yes, but remember that on STM32, normally the code is executing from the same flash memory you are trying to program and that the bus stalls during flash write and erase, such that if you are executing from flash, execution halts. For page erase, that can be several milliseconds - for parts with large pages, several hundred milliseconds even. That may mean that you fail to read characters on the UART if you are using polling or interrupt.
You can overcome this issue by protocol design. For example if you use a packet protocol where the last packet must be acknowledged before the next one is sent, you can use that as a flow control. Once you have collated a block of data to be written, you simply delay the acknowledgement of the last packet until after you have erased and/or written the data to flash. XMODEM-1K is a suitable protocol for that and despite its flaws its simplicity and support in common terminal emulator applications make it a good choice for this application.
Now all that said, you can increase the flash available to B1 by not buffering the image for B2 on B1 at all and simply implement a bi-directional pass-through such that the input on the UART of B1 is passed directly to the B1 RS-485 output, (surely also a UART so your port naming is ambiguous), and B1 RS-485 input passed directly to the UART output. That way B1 becomes "transparent" and the update tool will appear to be communicating directly with B2. That is perhaps far simpler and faster, and if the bootloader is "fail-safe" as described above, will still allow retries following interruption.
The pass-through function might be part of B1's application or a "mode" of the bootloader. The pass-through mode might be invoked by a particular boot command or you might have the application pass a "boot mode" command via the SRAM mechanism described earlier.
In either case ideally you would have identical bootloader code on both B1 and B2 for simplicity and flexibility. There is no reason why that should not be the case; they are both receiving the updates over UART.
We want our device (STM32-F446RE running FreeRTOS + Telit ME310G1 modem) to communicate to the AWS cloud. We are trying to follow the Cellular Interface Library Demo, in particular following this- diagram
We are using coreMQTT Agent, MbedTLS libraries, the amazon communication interface implementation for UART and amazon UART API implementation.
UART using 115200 baud rate.
Currently failing on the Cellular_Init function when trying to send the first AT command to the modem, specifically when calling the HAL_UART_TRANSMIT_IT function from the above comm interface send function. While debugging we see that the USART1_IRQHandler is called infinite times and nothing is sent through the UART communication.
We are using the default handler, do we need to implement it in any way?
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
Any help will be appreciated.
Thanks in advance,
Guy
Sounds like the UART line from HW point of view are not in a good state (High).
Did you check and ensure that the Power On sequence is done correctly? (Power On telit pin shall be high).
I expect you have some logic to translate the 1.8v to 3.3v and vice versa.
Can you check by measuring the different voltage that everything is OK?
If you verified all the point above.
Do you perform a reset on the telit side before starting the AT communication?
This ensure that you don't leave the module into a data mode where no AT commande are possible
Yacine
I am trying to play around with stm32 uart in polling mode. the transmission part is working properly and I read proper characters that I send from the MCU, however the reception part is not working properly.
This is a welcome message
ÿÿÿÿ
The first line is send from MCU to PC, the MCU then waits for reception. As I understand that HAL_USART_Receive is a blocking call so it should wait for user to input character from the terminal, however before i can write any characters and send them over to MCU, it moves over to the next line which is an infinite while loop. I cant understand why is it not pausing at the receive method. I debugged and checked the live expression windows, during initialization I set the receive buffer to '\0' however after passing through the HAL_Receive method the value of the buffer becomes 127. see the attached image for value stored in the buffer.
output
Can you please help me understand what am I doing wrong. My code is shown below
HAL_Init(); // Initializing HAL.
SystemClockConfig();
USART3_Init();
uint8_t tx_data[] = "This is a welcome message\r\n";
uint16_t tx_len = sizeof(tx_data);
HAL_USART_Transmit(&husart3, tx_data, tx_len, HAL_MAX_DELAY);
uint8_t rx_data[5]={0};
uint16_t rx_len = sizeof(rx_data);
HAL_USART_Receive(&husart3, rx_data, rx_len, HAL_MAX_DELAY);
while(1)
{
}
You said you are using the USART in UART mode (I assume you mean asynchronous mode) but your Handle (husart) is synchronous, and the HAL methods you are using are synchronous as well?
Your RX pin on your STM32 is held high which is why you get 0xFF (127) in your buffer when you call your receive function.
I think you have selected an incorrected setting in your code generator, are you using CubeIDE? If so, go to USART and choose "asynchronous" from the options and regenerate. You'll notice your handle change from husart to huart. The HAL functions for sending and transmitting are HAL_UART_Transmit() and HAL_UART_Receive(). Using these the same way in your current code will give the results you are looking for.
I'm trying to start a DMA transfer on my stm32f412, and I've got everything set up to the point where I'm setting the control registers on the DMA channels/streams for TX and RX. I am able to set the enable (Bit 0) on the TX, but not the RX.
The datasheet has 3 options for the bit being cleared by hardware: 1.) On a DMA end of transfer (stream ready to be configured) 2.) If a transfer error occurs on the AHB master buses 3.) When the FIFO threshold on memory AHB port is not compatible with the size of the burst.
I don't think it could be the first or the third, because the DMA transfer hasn't even started yet, and there isn't a burst configured, it's just a single transfer. I'm not quite certain what the second means, but there aren't transfer errors marked in the error registers.
Any avenues to look into would be appreciated
Edit: Ugh, I was looking at the wrong registers for to find the DMA_LISR and _HISR. There was a transfer error on my RX channel.
From the description of DMA_SxCR_EN bit in the reference manual:
Note: Before setting EN bit to '1' to start a new transfer, the event flags corresponding to the
stream in DMA_LISR or DMA_HISR register must be cleared.
In my experience, these event flags include not only the error flags, but also the regular event flags like Transfer Complete or Half Transfer. In some cases, I also ended up clearing FIFO error flag, although I can't remember the reason behind it.
This problem manifests itself as "DMA works only once". In your case, it doesn't work even once, so there can be other problems. Still, I think it's worth trying to clear all the status flags before enabling the stream.
I'm trying to implement simple echo for UART on stm32f4 discovery board (using freertos). As far as I understand it should be very easy.
First I call HAL_UART_Receive_IT(&huart3, &rx_char,1) in a task. And after receiving an interrupt USART3_IRQHandler should trigger. And then in HAL_UART_RxCpltCallback I'll do HAL_UART_Transmit(&huart3, &rx_char, 1, timeout) and maybe re-enable it with HAL_UART_Receive_IT. Did I get the idea right? Should it work?
But in my case it doesn't. I'm trying to send a char from the terminal, but USART3_IRQHandler is never triggered. Nothing happens.
The code was generated using Stm32CubeMX with Freertos, USART3, NVIC and with USART3 global interrupt enabled.
Also I call __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE) in main function.
What is wrong? HAL_UART_Transmit works perfectly.
HAL isn't ideal library. You must check registers, if something went wrong.
Your problem is looking like non-working NVIC. Check it, and if it wasn't turning on use something like - NVIC_EnableIRQ(USART3_IRQn);
Or may be wasn't switch on RE register in CR1 in USART3.
Anyway, I'm repeating - check registers.