STM32 UART multiprocessor mode with address mark detection. Intended data bytes are interpreted as address bytes - stm32

I have configured the UART for multiprocessor communication over RS485. I can receive and transmit data correctly. After waking up (RWU=0) when the correct address is received subsequent bytes should be received normally, and not interpreted as another address is my understanding. But if the intended data bytes contains a '1' as MSB it is interpreted as an address. Now it is clear from the documentation that this is the correct behavior, but after the correct address is received (RWU set to 0 and RXNE set to 1, confirmed by debugging) I can only receive data with a value less than the defined address. For example, if I set wordlength to 9bit and the address to 4, the correct address will be 132 (10000100) which is expected (address length is 8 bit in this case I think, because ADDM7 is set). But subsequent bytes are still interpreted as addresses. Sending 132,55,45,150 (via RealTerm) will only receive 132,55,45 as 132 is the correct address and 44,55 has '0' as MSB. 150 is interpreted as a new address because of the '1' in the MSB and RWU is again set to 1 since it is the incorrect address and I can no longer receive data.
My question is how can i interpret subsequent bytes after an correct address as pure data bytes, before I go back to listening for an address again? If I understand correctly, RWU and RXNE is set by HW in this mode? Or is there something specific I should do in FW? My implementation is interrupt-based for now.
The MCU I use is F303K8.
I'll attach some pictures, code and documentation for details and clarity.
Thanks!
Reference manual:
Code and debug:
int main(void)
{
/* USER CODE BEGIN 1 */
testvar = testvar + 1;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart1, (uint8_t*)test, strlen(test), 100);
HAL_MultiProcessor_EnableMuteMode(&huart1);
HAL_MultiProcessor_EnterMuteMode(&huart1);
/* Listen for address */
if(HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_buffer, BUFSIZE) != HAL_OK){
Error_Handler();
}
//HAL_MultiProcessor_EnterMuteMode(&huart1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//HAL_Delay(500);
//testvar = testvar + 1;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//testvar = 64;
/* ADDRESS received! Begin listening for data(COMMANDS)
* When CMDs handled, enter mute mode again in order to listen for address byte again */
if(HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_buffer, BUFSIZE) != HAL_OK){
Error_Handler();
}
}
Oscilloscope:

Related

STM32H7 bank swap break at address 0x81006fe

I am trying to do a bank swap with the ST32 H743ZI2. I wasted much of time to fix it but I didn't get it. Maybe because I'm new in STM32 controllers.
I copied the bank swap code from STM32CubeH7 Firmware Examples and did a few modifications regarding to gpio configuration in CubeMX. I did them because I want to implicate the code in a existing project without the stm32h7xx_nucleo headers.
Following the Code for Bank1:
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
while (1)
{
/* Wait for BUTTON_USER is released */
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1)
{
while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1);
/* Get the Dual boot configuration status */
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Get FLASH_WRP_SECTORS write protection status */
OBInit.Banks = FLASH_BANK_1;
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Check Swap FLASH banks status */
if ((OBInit.USERConfig & OB_SWAP_BANK_ENABLE) == OB_SWAP_BANK_DISABLE)
{
/*Swap to bank2 */
/*Set OB SWAP_BANK_OPT to swap Bank2*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_ENABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
HAL_NVIC_SystemReset();
}
else
{
/* Swap to bank1 */
/*Set OB SWAP_BANK_OPT to swap Bank1*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_DISABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
}
}
else
{
#ifdef FLASH_BANK1
/* Toggle LED1 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
/*Turn Off LED2*/
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, 0);
#else
/* Toggle LED2 */
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1);
/* Turn off LED1 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
#endif
/* Insert 100 ms delay */
HAL_Delay(100);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
The code for bank1 and bank2 are equal except linkerscript.
I split Flash in two areas which have 1024kb each. In following you can see the code for bank1.
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
In linkerscript for bank2 I changed flash start address to 0x08100000.
Now I have following problem. If I load in order code for bank1 and code for bank2 press the Button1 and Press the Resetbutton I get following error message:
Break at address "0x81006fe" with no debug information available, or outside of program code.
I already successfully checked if there is placed some code with STM32 Utility.
If I load the codes in reverse order the banks get swapped once. Independently if Button1 gets pressed before system reset or not..
I already checked some forums without success.
Does anyone know where the problem could be?
There were two problems in code.
Linker script was splited up in two parts. Linker script had to rebuild in original state regarding to flash. The code for bank2(0x081000000) needs to locate with an extern software like stm32 utility now.
Vector table was relocate at wrong address in system_stm32h7xx.c

STM32 HAL stall in a loop

I'm just starting with STM32 devices and STM32Cube.
I made a simple blink code but the program get stuck in a forever loop in the HAL code.
__weak uint32_t HAL_GetTick(void)
{
return uwTick;//<- Always performs this code in a loop after my code calls delay routine
}
My code is pretty simple and GPIO13 is set it as OUTPUT.
The Clk is external with PLL * 9 = 8MHz * 9 = 72MHz
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t x=0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
x++;
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

LoRaWAN join after standby

I'm sending some information using LoRaWAN on a STM32WB and after that, I enter standby mode.
The problem is that after my standby, a new join is done.
I have heard that my join could be keep in memory using MIB functions but I don't manage to use them properly and continue to do a join do not make a join at all...
Does somebody know how to use them or a good tutorial somewhere? (I didn't find anything for the moment)
Here is what I am trying actually :
uint32_t last_time = 0;
int main(void)
{
/* USER CODE BEGIN 1 */
data_t data;
LoraFlagStatus join_status = LORA_RESET;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_LPTIM1_Init();
MX_LPUART1_UART_Init();
MX_RF_Init();
HW_RTC_Init();
MX_SPI1_Init();
MX_I2C3_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
/* Reduce the System clock to below 2 MHz */
SystemClock_Decrease();
/* Set regulator voltage to scale 2 */
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2);
HAL_PWREx_EnableLowPowerRunMode();
float iaq;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_NETWORK_ACTIVATION;
LoRaMacMibGetRequestConfirm( &mibReq );
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
lora_init();
join_status = lora_join();
}
while (1)
{
//sensor code and lora send
lora_update(); /* Must be called for the LoRa stack to work */
pres = false;
/* Enable and set RTC_WKUP_IRQ */
HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
/* Check if the system was resumed from StandBy mode */
/* Note: On STM32WB, both CPU1 and CPU2 must be in standby mode to set the entire system in standby mode */
if( (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
&& (__HAL_PWR_GET_FLAG(PWR_FLAG_C2SB) != RESET)
)
{
/* Clear Standby flag */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_C2SB);
}
/* Insert 5 seconds delay */
HAL_Delay(5000);
/* Disable all used wakeup sources*/
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
/* Clear all related wakeup flags */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* Re-enable wakeup source */
/* ## Setting the Wake up time ############################################*/
HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 60, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);;
/* Specific procedure on STM32WB, in case of initial power-up and RF stack no started */
if( (LL_PWR_IsActiveFlag_C1SB() == 0)
|| (LL_PWR_IsActiveFlag_C2SB() == 0)
)
{
/* Set the lowest low-power mode for CPU2: shutdown mode */
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
}
/* Enter the Standby mode */
HAL_PWR_EnterSTANDBYMode();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/**
* #brief System Clock Speed decrease
* The system Clock source is shifted from HSI to MSI
* while at the same time, MSI range is set to RCC_MSIRANGE_5
* to go down to 2MHz
* #param None
* #retval None
*/
void SystemClock_Decrease(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
/* Select MSI as system clock source */
/* Note: Keep AHB and APB prescaler settings from previous structure initialization */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Disable PLL to reduce power consumption since MSI is used from that point */
/* Change MSI frequency */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
/* USER CODE END 4 */

STM32 HAL USART receive by interrupt

I have some trouble to receive data over the USART. What I actually want to achieve ist, that I can receive a command over USART with no specific length (only a maximum possible length). So I use the interrupt routine to check each character received, but I somehow still cannot achieve what I want. The routine is called each time I receive a new character, but somehow HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx) does not upgrade in realtime, then I don't see the received character when I check rx_data[pointer], but a few time later it is in the rx_data buffer.
What I have so far:
int pointer =0;
...
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if ( USART1->ISR & UART_IT_TXE) {
}
if ( USART1->ISR & UART_IT_RXNE) {
HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx);
if(rx_data[pointer]=='\0') {
pointer=0;
readCommand(rx_data);
clearBuffer(rx_data,buff_size_rx);
} else {
pointer++;
if(pointer>=buff_size_rx) {
pointer=0;
}
}
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
HAL_UART_Receive_IT() is not meant to be called from an interrupt handler that way, but to initiate receiving a fixed number of bytes via interrupt.
A possible workaround is to check your input buffer after HAL_UART_IRQHandler() completes, i.e. in the /* USER CODE BEGIN USART1_IRQn 1 */ section. When a command is processed, you can reset pRxBuffPtr and RxXferCount in the handle structure to their original values to start from the start of the buffer again.
Another horrible possible workaround would be to call HAL_UART_Receive_IT() with a buffer size of 1, and set up a HAL_UART_RxCpltCallback() handler that checks the received byte each time, and calls HAL_UART_Receive_IT() again when necessary.
Of course you could do it without HAL, as PeterJ and others (always) suggest.
You've already implemented pin and interrupt setup, leave them unchanged at first.
Calculate the UART->BRR value according to the reference manual, or copy the relevant code from hal.
set UART->CR1=USART_CR1_RE|USART_CR1_TE|USART_CR1_UE|USART_CR1_RXNEIE; Now, you are getting interrupts.
In the interrupt function, read UART->SR into a temporary variable, and examine it.
Read UART->DR when there is a received byte waiting, do the error handling otherwise (later).
Get rid of the rest of the HAL calls when the above is working.
Interrupt response and processing time is often critical in embedded applications, and the HAL just wastes a lot of that.
The normal HAL library is not useful for continuous reception or commands with different length.
If you have the complete HAL package installed, you could look at the examples for the LowLevel interface.
Projects\STM32F411RE-Nucleo\Examples_LL\USART\USART_Communication_Rx_IT_Continuous
The main thing is to set you usart to continuous reception:
void Configure_USART(void) {
/* (1) Enable GPIO clock and configures the USART pins *********************/
/* Enable the peripheral clock of GPIO Port */
USARTx_GPIO_CLK_ENABLE();
/* Configure Tx Pin as : Alternate function, High Speed, Push pull, Pull up */
LL_GPIO_SetPinMode(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_MODE_ALTERNATE);
USARTx_SET_TX_GPIO_AF();
LL_GPIO_SetPinSpeed(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_PULL_UP);
/* Configure Rx Pin as : Alternate function, High Speed, Push pull, Pull up */
LL_GPIO_SetPinMode(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_MODE_ALTERNATE);
USARTx_SET_RX_GPIO_AF();
LL_GPIO_SetPinSpeed(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_PULL_UP);
/* (2) NVIC Configuration for USART interrupts */
/* - Set priority for USARTx_IRQn */
/* - Enable USARTx_IRQn */
NVIC_SetPriority(USARTx_IRQn, 0);
NVIC_EnableIRQ(USARTx_IRQn);
/* (3) Enable USART peripheral clock and clock source ***********************/
USARTx_CLK_ENABLE();
/* (4) Configure USART functional parameters ********************************/
/* TX/RX direction */
LL_USART_SetTransferDirection(USARTx_INSTANCE, LL_USART_DIRECTION_TX_RX);
/* 8 data bit, 1 start bit, 1 stop bit, no parity */
LL_USART_ConfigCharacter(USARTx_INSTANCE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
/* No Hardware Flow control */
/* Reset value is LL_USART_HWCONTROL_NONE */
// LL_USART_SetHWFlowCtrl(USARTx_INSTANCE, LL_USART_HWCONTROL_NONE);
/* Oversampling by 16 */
/* Reset value is LL_USART_OVERSAMPLING_16 */
// LL_USART_SetOverSampling(USARTx_INSTANCE, LL_USART_OVERSAMPLING_16);
/* Set Baudrate to 115200 using APB frequency set to 100000000/APB_Div Hz */
/* Frequency available for USART peripheral can also be calculated through LL RCC macro */
/* Ex :
Periphclk = LL_RCC_GetUSARTClockFreq(Instance); or
LL_RCC_GetUARTClockFreq(Instance); depending on USART/UART instance
In this example, Peripheral Clock is expected to be equal to
100000000/APB_Div Hz => equal to SystemCoreClock/APB_Div
*/
LL_USART_SetBaudRate(USARTx_INSTANCE, SystemCoreClock/APB_Div, LL_USART_OVERSAMPLING_16, 115200);
/* (5) Enable USART *********************************************************/
LL_USART_Enable(USARTx_INSTANCE);
}
The USART IT Handler should look like
void USARTx_IRQHandler(void)
{
/* Check RXNE flag value in SR register */
if(LL_USART_IsActiveFlag_RXNE(USARTx_INSTANCE) && LL_USART_IsEnabledIT_RXNE(USARTx_INSTANCE))
{
/* RXNE flag will be cleared by reading of DR register (done in call) */
/* Call function in charge of handling Character reception */
USART_CharReception_Callback();
}
else
{
/* Call Error function */
Error_Callback();
}
}
The last thing to set up is the Callback
void USART_CharReception_Callback(void);
Where you could put the bytes into an buffer and handle it in the main loop or where you want.
Since I stumbled over the problem today and could not find a good solution to it, I like to present a very simple one, using most of the HAL but avoiding the problems described...
Short verison of my approach is:
In the last user code section (for the appropriate USART instance, if using more than one) of void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle), enable the IRQ with:
__HAL_UART_ENABLE_IT(&huartx, UART_IT_RXNE);
Then put the desired code in your interrupt function:
void USART3_IRQHandler(void) {
/* USER CODE BEGIN USART3_IRQn 0 */
CallMyCodeHere();
return; // To avoid calling the default HAL handler at all
// (in case you want to save the time)
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3); // This is the CubeMX generated HAL handler
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
Don't use HAL_UART_Receive_IT anywhere, it will disable the IRQ and you need to re-enable it, if you want to get called with every reception.
The long version could be found in my post here...
Here is the full example of receiving data and idle line detection by interrupts:
Enable the receive interrupts and idle line detection in main.c:
/* USER CODE BEGIN USART2_Init 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); // enable receive intterupts
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // enable idle line detection
/* USER CODE END USART2_Init 2 */
Sort out the idle line event from within USARTx_IRQHandler in stm32f4xx_it.c:
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart2); // taken from https://electronics.stackexchange.com/questions/471272/setting-up-stm32-timer-for-uart-idle-detection#comment1353999_480556
uart2_idleHandler();
} else {
uart2_handler();
}
return;
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
Testing:
Create the following handlers:
char my_uart_buffer[256];
int my_uart_buffer_index = 0;
void uart2_handler(void){
char buff;
HAL_UART_Receive (&huart2, (uint8_t *)&buff, 1, 400);
my_uart_buffer[my_uart_buffer_index++] = buff;
}
void uart2_idleHandler(){
my_uart_buffer_index = 0;
}
Open a serial port client in your PC, setup as 115200 baud, 8N1.
Set a breakpoint to uart2_idleHandler().
Send "Hello world".
You can examine your buffer by p/c *my_uart_buffer#20 when breakpoint hits.
Example Project
Here is the full example that runs on STM32F407 Discovery board.
You can make it work using HAL! It may not be as elegant as other implementations but it is doable.
You have to create an error handler function and then the function that calls the HAL_UART_RCV_IT must flush the UART RX whenever there is an overrun error.
In addition, I work with two buffers. While the Interrupt is filling one buffer the main loop is emptying the other.
Here it how it is working well for me:
typedef enum
{
UARTREADY = 0,
UARTBUSY = 1,
UARTDATA = 2,
UARTERROR = 3
} enumUartStatus;
while(1){
if(UARTREADY == isUsart3RxReady()){
Usart3RxBuffer((char *)&SOMRxBytesBuffer[use_buffer_index], RCV_BUFFER_BANK_SIZE); // receive bytes in the raw buffer
if(use_buffer_index == RCV_BUFFER_BANK1_INDEX){
use_buffer_index = RCV_BUFFER_BANK2_INDEX;
rxb1_stats++;
}else{
use_buffer_index = RCV_BUFFER_BANK1_INDEX;
rxb2_stats++;
}
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart == NULL){
return;
}
if(huart->Instance == USART3){
if(HAL_UART_GetError(huart) == HAL_UART_ERROR_FE){
Usart3Ready = UARTREADY;
}else{
Usart3Ready = UARTERROR;
}
}
}
void Usart3RxBuffer(char *buffer, unsigned short rxbuffersize){
/* Reset transmission flag */
if(Usart3Ready != UARTREADY)
{
return;
}
if(HAL_UART_GetState(&huart3) == HAL_UART_STATE_READY){
/*##-3- Put UART peripheral in reception process ###########################*/
if (HAL_UART_Receive_IT(&huart3, (uint8_t *)buffer, rxbuffersize) != HAL_OK)
{
// TODO: Error_Handler();
DEBUG_TRACE(DEBUG_MSK_MAIN, "UART3 error starting receiver!\r\n");
}else{
// An interrupt HAL_UART_ErrorCallback hit right here !!!!
// There is an overrun error happening here so we have to retry
// this is because we are using the Receive_IT in a continous communication and there is no handshake or flow control
if(Usart3Ready != UARTERROR){
/* Busy waiting to receive bytes */
Usart3Ready = UARTBUSY;
}
}
}
if(Usart3Ready == UARTERROR){
HAL_UART_AbortReceive_IT(&huart3);
Usart3Ready = UARTREADY;
}
}

Cannot mount SD using FatFS on STM32

I'm trying to write to a MicroSD-Card using STM32F405 chip.
The pins are connected correctly and each pin on the MicroSD-Card slot can be written to by using HAL_GPIO_WritePin. (Messured with ossciloscope) I'm using CubeMX to generate the init code for TrueStudio, so hopefully everything is ok there as well. But when I run the following code, f_mount returns FR_DISK_ERR. The MicroSD-Card can be written to and read from. If I use a different Device number, i.e. "1:", I get FR_INVALID_DRIVE
So my question is: what could cause FR_DISK_ERR except a faulty MicroSD-Card?
Here is my code so far:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_FATFS_Init();
/* USER CODE BEGIN WHILE */
FATFS fileSystem;
FIL testFile;
uint8_t testBuffer[16] = "SD write success";
UINT testBytes;
FRESULT res;
while((res = f_mount(&fileSystem, SD_MOUNT_PATH, 1)) != FR_OK){
printf("%d", res); //used to debug res, only for TrueStudio Debugger
}
uint8_t path[13] = "testfile.txt";
path[12] = '\0';
res = f_open(&testFile, (char*)path, FA_WRITE | FA_CREATE_ALWAYS);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
res = f_write(&testFile, testBuffer, 16, &testBytes);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
res = f_close(&testFile);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}
in MX_FATFS_Init() FATFS_LinkDriver(&SD_Driver, SD_Path) is called and returns 0.
Without the SD_MOUNT_PATH macro, does the f_mount call look like this:
f_mount(&fileSystem, "0:", 1) ?'
Are you saying that f_open, f_write return FR_OK even if f_mount fails?!
FR_DISK_ERR usually means disk_read() or disk_write() failed. Try giving 100ms or 1 sec delay before using f_mount() and between between fatfs function calls.