How to read FIFO Data from MAX30100 using STM32F4 - c

i'm monitorating heart rate by the MAX30100(https://img.filipeflop.com/files/download/Datasheet_MAX30100.pdf) using the MCU STM32F4. I'm trying read the IR and RED data from the FIFO, but all returns are ZERO. The method MAX30100_Get_Num_Samples() returns 8. I modeled the code using the pseudo code from datasheet of MAX30100. I tried several solutions for my problem but doesn't work. I dont know if i'm following the right way to get data from the FIFO. My code:
I2C_HandleTypeDef hi2c3; //i2c used
uint16_t RED[50] = {0}, IR[50] = {0}; //buffers for RED and IR
uint8_t buffOximeter[5];
char buffer[32];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C3_Init();
MX_USB_DEVICE_Init();
MAX30100_Init();
while (1)
{
uint8_t numSamples = MAX30100_Get_Num_Samples();
MAX30100_Read_HeartBeat(numSamples);
for(int i = 0; i < numSamples; i++)
{
sprintf(buffer, "Amostra %d: %d / %d\n\r", i , IR[i], RED[i]);
CDC_Transmit_FS((char*)buffer, 50);
}
}
}
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 400000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
}
void MAX30100_Init(void)
{
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x06,1,0x02,1,1000); //set heart rate mode
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x09,1,0xFF,1,1000); //i50 ledCurrent
uint8_t sr = 0x01, pw = 0x3;
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x07,1,(sr<<2)|pw,1,1000); //sr100, pw1600
HAL_Delay(50);
}
void MAX30100_Read_HeartBeat(uint8_t num)
{
for(int i=0;i<num;i++)
{
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x02,1,1000); //send fifo_wr_ptr
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
uint8_t data;
HAL_I2C_Master_Receive(&hi2c3,0x57,&data,1,1000); //read fifo_wr_ptr
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x05,1,1000); //send adress fifo data
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
HAL_I2C_Mem_Read(&hi2c3,0x57,0x05,1,&buffOximeter,4,1000); //read fifo data
IR[i] = (buffOximeter[0] << 8) | buffOximeter[1];
RED[i] = (buffOximeter[2] << 8) | buffOximeter[3];
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x04,1,1000); //send adress fifo_rd_ptr
HAL_Delay(100);
}
}
int MAX30100_Get_Num_Samples(void)
{
uint8_t wrPtr, rdPtr;
HAL_I2C_Mem_Read(&hi2c3,0x57,0x02,1,&wrPtr,1,1000);
HAL_Delay(50);
HAL_I2C_Mem_Read(&hi2c3,0x57,0x04,1,&rdPtr,1,1000);
HAL_Delay(50);
return (abs( 16 + wrPtr - rdPtr ) % 16);
}

connect the interrupt output pin (pin 13 active low) to an interrupt control pin on the cpu.
setup your cpu to be interrupted when the device indicates some event ready
Then, still in your interrupt handler function, read register 0 and determine which data is ready,.
the referenced datasheet, approx page 14 lists the order of communication events needed. Note that the posted code is NOT following the specified order of communication events
page 16, register 7, indicates how to initialize the SPO2 for the desired mode of operation

Related

LIS3DSH x y z axis is incorrect

I have tried to work with LIS3DSH sensor using SPI protocol. I applied procedures on STM32L0 Discovery kit LoRa. But it didn't work.
My problem is The LIS3DSH x-y-z-axis output value is invalid and the value is not changed. No matter which direction I rotate the device but I check ID of LIS3DSH is correct ( 0011 1111)
Component
STM32L0 Discovery kit LoRa
LIS3DSH (https://www.amazon.com/LIS3DSH-High-Resolution-Three-axis-Accelerometer-Triaxial/dp/B07QS5D9K9/ref=sr_1_4?dchild=1&keywords=LIS3DSH&qid=1615701212&sr=8-4)
init SPI2
...
void HW_SPI2_Init(void)
{
/*##-1- Configure the SPI2 peripheral */
/* Set the SPI parameters */
hspi2.Instance = SPI2;
hspi2.Init.BaudRatePrescaler = SpiFrequency(10000000);
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA = 1
// hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
// hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCPolynomial = 10;
SPI2_CLK_ENABLE(); // Enable clock for SPI 2
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-2- Configure the SPI GPIOs */
HW_SPI2_IoInit();
}
...
initialization LIS3DSH
void HW_SPI2_IoInit(void)
{
GPIO_InitTypeDef initStruct = {0};
initStruct.Mode = GPIO_MODE_AF_PP;
initStruct.Pull = GPIO_PULLUP ;
initStruct.Speed = GPIO_SPEED_FAST;
initStruct.Alternate = SPI2_AF;
HW_GPIO_Init(LIS3DH_SCLK_PORT, LIS3DH_SCLK_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MISO_PORT, LIS3DH_MISO_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MOSI_PORT, LIS3DH_MOSI_PIN, &initStruct);
initStruct.Mode = GPIO_MODE_OUTPUT_PP;
initStruct.Pull = GPIO_NOPULL;
HW_GPIO_Init(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, &initStruct);
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
CS ON or OFF
void HW_SPI2_CS_ON (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 0);
}
void HW_SPI2_CS_OFF (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
Read ID
uint8_t LIS3DSH_DH_CHECK_ID (void)
{
uint8_t addr = LIS3Dx_WHO_AM_I_ADDR | LIS3Dx_READ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
UsingTypeint_LIS3DSH_DH.ID = au8BufferRead_SPI2[0];
return UsingTypeint_LIS3DSH_DH.ID;
}
Read X axis ( only) (Incorrect)
void LIS3DSH_DH_GET_XYZ (void)
{
uint8_t addr = LIS3Dx_OUT_X_L_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
addr = LIS3Dx_OUT_X_H_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
}
HW_SPI2_1byte_Write_and_Read
bool HW_SPI2_SPI_1byte_Write_and_Read(uint8_t u8Address)
{
if(HAL_SPI_Transmit(&hspi2, (uint8_t *)&u8Address, 1, HAL_MAX_DELAY) == HAL_OK){
if(HAL_SPI_Receive(&hspi2, (uint8_t *)&au8BufferRead_SPI2[0], 1, HAL_MAX_DELAY) == HAL_OK){
return true;
}
}
return false;
}
Signal
output X L
output X H
Am not sure if you are using the state machine and register accesses of the LIS3DSH accurately.
As a reference see the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h (start at line 95) and the code in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.c
The function that actually writes and reads the SPI bus is void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) and void ACCELERO_IO_Read(uint8_t *pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead)
This is defined in https://documentation.help/STM32F4-Discovery-BSP/stm32f4__discovery_8c_source.html at lines 560 and 594
In void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) the actual SPI write is done at lines 574 to 582
00574 SPIx_WriteRead(WriteAddr);
00577 while(NumByteToWrite >= 0x01)
00578 {
00579 SPIx_WriteRead(*pBuffer);
00580 NumByteToWrite--;
00581 pBuffer++;
00582 }
(as always with SPI first activate register, then write data...)
In SPIx_WriteRead(WriteAddr); the WriteAddr is taken from the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h, start at line 9
(the above code by STM for the LIS3DSH is nice work, this implementation is very clean and structured)
The datasheet of the LIS3DSH is in https://www.st.com/resource/en/datasheet/lis3dsh.pdf, the reference manual is far more detailed it is in https://www.st.com/resource/en/application_note/dm00026768-lis3dsh-3axis-digital-output-accelerometer-stmicroelectronics.pdf it also includes explanation of the state machines, that have to be configured before the device works

Issue in interfacing SPI e-ink display with PIC 18F46K22

I am using a PIC 18F46K22 in SPI master mode to communicate with a Waveshare 1.54" ePaper Module. The FOSC frequency is 8Mhz internal and SPI configuration is FOSC/4. So when I check the output on logic-analyzer some output bits are differ from expected. And there is some deviation in SCL.
#include <xc.h>
#include "config.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "main.h"
//#define _XTAL_FREQ 8000000
#define SPI1_DUMMY_DATA 0x0
#define SPI_RX_IN_PROGRESS 0x0
#define MY_BUFFER_SIZE 25
extern UBYTE EPD_Init(const unsigned char* lut);
unsigned char myWriteBuffer[100]="Hi I'm master..";
uint8_t myReadBuffer[100];
uint8_t total;
uint8_t temp;
uint8_t my_data = 0x58;
void UART_Init(void)
{
//69
SPBRG2 = 69;
TXSTA2bits.BRGH = 1;
BAUDCON2bits.BRG16 = 1; // Divisor at 8 bit
TRISDbits.TRISD6 = 0;
TRISDbits.TRISD7 = 1;
RCSTA2bits.SPEN = 1; // Enable serial port
TXSTA2bits.SYNC = 0; // Async operation
TXSTA2bits.TX9 = 0; // No tx of 9th bit
RCSTA2bits.RX9 = 0; // No rx of 9th bit
TXSTA2bits.TXEN = 1; // Enable transmitter
RCSTA2bits.CREN = 1; // Enable receiver
}
void UART_Putch(unsigned char bt)
{
while (!PIR3bits.TX2IF); // hold the program till TX buffer is free
TXREG2 = bt; //Load the transmitter buffer with the received value
}
void UART_Print(unsigned const char *ptr)
{
while (*ptr != 0)
{
UART_Putch(*ptr++);
}
}
unsigned char UART_getch() {
unsigned char temp;
if (RCSTA2bits.OERR) // check for Error
{
RCSTA2bits.CREN = 0; //If error -> Reset
//__delay_ms(10);
RCSTA2bits.CREN = 1; //If error -> Reset
}
while (!PIR3bits.RC2IF); // hold the program till RX buffer is free
temp = RCREG2;
return temp; //receive the value and send it to main function
}
void main()
{
ANSELA = 0;
ANSELB = 0;
ANSELC = 0;
ANSELD = 0;
TRISBbits.TRISB0 = 0; //RST Pin OUTPUT
TRISBbits.TRISB1 = 0; //DC Pin OUTPUT
TRISBbits.TRISB2 = 0; //CS Pin OUTPUT
TRISBbits.RB3 = 1; //BUSY Pin INPUT
// int i;
TRISD =0;/* PORT initialize as output */
EPD_RST_PIN = 0;
EPD_DC_PIN = 0;
//OSCCON = 0x72; /* Use internal osc. frequency 16 MHz */
OSCCONbits.SCS = 0b10; //Frequency & PLL SETUP
OSCCONbits.IRCF = 0b110; //8 MHz
while (!OSCCONbits.HFIOFS);
OSCTUNEbits.PLLEN = 0; //PLL disable
UART_Init();
SPI_Init_Master(); /* Initialize SPI communication as a master */
if(EPD_Init(lut_full_update) != 0) {
UART_Print("e-Paper init failed\r\n");
while(1);
}
UART_Print("e-Paper init\r\n");
for(uint8_t i = 0; i < 10; i++){
__delay_ms(10);
}
EPD_Clear();
UART_Print("e-Paper cleared\r\n");
for(uint8_t i = 0; i < 10; i++){
__delay_ms(50);
}
while(1)
{
// total = 0;
// //do
// //{
// LATAbits.LATA5=0;
// //total = SPI1_Exchange8bitBuffer(SPI1_DUMMY_DATA, MY_BUFFER_SIZE, &myReadBuffer[total]);
// total = SPI1_Exchange8bit(my_data);
//
// LATAbits.LATA5=1;
// __delay_ms(500);
// __delay_ms(500);
// // Do something else...
//
// //} while(total < MY_BUFFER_SIZE);
// //while(1);
//
// EPD_Clear();
//
// __delay_ms(500);
}
}
void SPI_Init_Master()
{
/* PORT definition for SPI pins*/
TRISCbits.TRISC4 = 1; /* RB0 as input(SDI) */
TRISCbits.TRISC3 = 0; /* RB1 as output(SCK) */
// TRISBbits.TRISB2 = 0; /* RA5 as a output(SS') */
TRISCbits.TRISC5 = 0; /* RC7 as output(SDO) */
/* To initialize SPI Communication configure following Register*/
EPD_CS_PIN = 1;
SSP1STAT=0x00; /* Data change on rising edge of clk , BF=0*/
SSP1CON1=0x20; /* Slave mode,Serial enable, idle state high for clk */
PIR1bits.SSP1IF=0;
/* Disable the ADC channel which are on for multiplexed pin
when used as an input */
ADCON0=0; /* This is for de-multiplexed the SCL
and SDI from analog pins*/
ADCON1=0x0F; /* This makes all pins as digital I/O */
}
uint8_t SPI1_Exchange8bit(uint8_t data)
{
// Clear the Write Collision flag, to allow writing
SSP1CON1bits.WCOL = 0;
SSP1BUF = data;
while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS)
{
}
return (SSP1BUF);
}
uint8_t SPI1_Exchange8bitBuffer(uint8_t *dataIn, uint8_t bufLen, uint8_t *dataOut)
{
uint8_t bytesWritten = 0;
if(bufLen != 0)
{
if(dataIn != NULL)
{
while(bytesWritten < bufLen)
{
if(dataOut == NULL)
{
SPI1_Exchange8bit(dataIn[bytesWritten]);
}
else
{
dataOut[bytesWritten] = SPI1_Exchange8bit(dataIn[bytesWritten]);
}
bytesWritten++;
}
}
else
{
if(dataOut != NULL)
{
while(bytesWritten < bufLen )
{
temp = SPI1_Exchange8bit(SPI1_DUMMY_DATA);
if(temp!=SPI1_DUMMY_DATA)
{
UART_Putch(temp); //uart print
dataOut[bytesWritten] = temp;
bytesWritten++;
}
__delay_ms(5);
}
}
}
}
return bytesWritten;
}
Compare your logic analyser SCK and MOSI timing with that specified for the part at https://www.waveshare.com/wiki/1.54inch_e-Paper_Module:
Note that the MOSI (SDIN) state must be stable on the rising edge of SCK (SCLK). In your case the MOSI transitions are synchronous with the rising edge, and you have a clock transition before the MOSI has the correct D7=0 state. SPI timing is defined by both clock polarity and clock phase - giving four possible clock modes. Compare the Waveshare timing diagram with the 18F46K22 datasheet:
The Waveshare diagram suggests that either CKP=1/CKE=0, or CKP=0/CKE=1 may be used, you have:
SSP1STAT=0x00 ;
SSP1CON1=0x20 ;
Which is CKP=0/CKE=0 (which correlates with your logic analyser trace).
You need on of either:
SSP1STAT=0x20 ; // CKE=1
SSP1CON1=0x20 ; // CKP=0
or
SSP1STAT=0x00 ; // CKE=0
SSP1CON1=0x30 ; // CKP=1
Since idle state (controlled by CKP) of SCK is a don't-care, I suggest leaving that as-is and using the first suggestion - that seems more intuitive somehow.
Note also that your logic analyser must also be set to the same phase/polarity clock mode in order for its presentation of the data to be correct.

Why stm32nucleo board uart can't receive message after almost three or four hundred times using HAL_UART_Receive_IT

I am developing uart communication on STMicroelectronics NUCLEO-G474RE Board(stm32G474RETX MCU, 64pins) using MDK-v5, but run into a perplexing problem these several days, make no progress on it and have to reach out to seek some help. If anyone could give me a right way to go, it would be appreciated greatly.
Code is not complicated, I use cubeMX to initialize the code base with usart2 configured, and use two threads based on cmsis v2 api for receiving occassinally and transmiting periodically(in 2 seconds).
The auto-generated usart2 init code
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_RTS;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
Interrupt call back code
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
printf("Interrupt error occured(0x%x)!!!\r\n", huart->ErrorCode);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart)
{
UNUSED(huart);
if(huart == &huart2 || huart == &huart3){
uint8_t aEnterLine[] = "\r\n";
//HAL_UART_Transmit(huart, aEnterLine, sizeof(aEnterLine), 0xFFFF);
//HAL_UART_Transmit(huart, gRxBuffer, 11, 0xFFFF);
//HAL_UART_Transmit(huart, aEnterLine, sizeof(aEnterLine), 0xFFFF);
//printf("%s\r\n", gRxBuffer);
if(g_cmdExecuting == 0)
osEventFlagsSet(evt_id, 0x00000001U);
}else if(huart == &huart1){
}else{
}
HAL_UART_Receive_IT(huart, (unsigned char*)gRxBuffer, 11);
}
int8_t app_usart_transmit(uint8_t* buf, uint8_t len)
{
return 0;
}
int8_t app_usart_init(UART_HandleTypeDef* huart)
{
if(huart == NULL)
return -1;
if(huart == &huart2 || huart == &huart3){
uint8_t aTxStartMessage[] = "\r\n****UART-Hyperterminal commmunication based on IT****"
"\r\nEnter 10 characters using keyboard: \r\n";
HAL_UART_Transmit(huart, aTxStartMessage, sizeof(aTxStartMessage), 0xFFFF);
}
clear_rx_buffer();
HAL_UART_Receive_IT(huart, (uint8_t*)gRxBuffer, 11);
return 0;
}
rx & tx worker code
extern osMutexId_t myMutex01Handle;
extern osEventFlagsId_t evt_id;
extern osEventFlagsId_t evt_id1;
osTimerId_t timer_id;
static osThreadId gTask1Handle;
static const osThreadAttr_t gTask1Attrbutes = {
.name = "Task1",
.priority = (osPriority_t) osPriorityAboveNormal,
.stack_size = 512
};
static osThreadId gTask2Handle;
static const osThreadAttr_t gTask2Attrbutes = {
.name = "Task2",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 512
};
uint8_t g_cmdExecuting = 0;
uint8_t g_SemExec = 0;
uint32_t timer_cnt;
void update_stat_timer(void* argument)
{
timer_cnt++;
//osMutexAcquire(myMutex01Handle, osWaitForever);
printf("update_stat_timer executes %u times, ====++++====++++\r\n", timer_cnt);
//osMutexRelease(myMutex01Handle);
}
void update_stat_task_run(void* argument)
{
uint32_t count;
for(;;){
osDelay(2000);
count++;
osMutexAcquire(myMutex01Handle, osWaitForever);
printf("update_stat_task_run executes %d times, ====++++====++++\r\n", count);
osMutexRelease(myMutex01Handle);
}
}
void exec_cmd_task_run(void* argument)
{
uint32_t flags;
for(;;){
flags = osEventFlagsWait(evt_id, 0x00000001U, osFlagsWaitAny, osWaitForever);
g_cmdExecuting = 1;
osMutexAcquire(myMutex01Handle, osWaitForever);
osDelay(1000);
printf("exec_cmd_task Print\r\n");
osMutexRelease(myMutex01Handle);
g_cmdExecuting = 0;
}
}
int8_t app_task_init()
{
osStatus_t status;
gTask1Handle = osThreadNew(exec_cmd_task_run, NULL, &gTask1Attrbutes);
gTask2Handle = osThreadNew(update_stat_task_run, NULL, &gTask2Attrbutes);
//uint32_t exec = 1;
//timer_id = osTimerNew(update_stat_timer, osTimerPeriodic, &exec, NULL);
//if(status != osOK){
//;
//}
//osTimerStart(timer_id, 2000U);
return 0;
}
My Question:
It could receive and transmit msg at very begining, but after receiving three or four hundred times, it couldn't receive the msg anymore while the transmitting is ok, and I also use the timer api to replace the transmitting thread, the result is the same, it couldn't receive any msg after hundreds times.
the testing result pic
You can perform the HAL status and error checks using uint32_t HAL_UART_GetError(UART_HandleTypeDef * huart) and HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart) (http://www.disca.upv.es/aperles/arm_cortex_m3/llibre/st/STM32F439xx_User_Manual/group__uart__exported__functions__group4.html)
The source code for HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) and HAL_UART_RxCplt_Callback() is in https://github.com/ARMmbed/mbed-hal-st-stm32cubef4/blob/master/source/stm32f4xx_hal_uart.c
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t tmp = 0;
tmp = huart->State;
if((tmp == HAL_UART_STATE_READY) || (tmp == HAL_UART_STATE_BUSY_TX))
{
if((pData == HAL_NULL ) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Check if a transmit process is ongoing or not */
if(huart->State == HAL_UART_STATE_BUSY_TX)
{
huart->State = HAL_UART_STATE_BUSY_TX_RX;
}
else
{
huart->State = HAL_UART_STATE_BUSY_RX;
}
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
Note that the HAL mutually uses locking mechanisms (__HAL_LOCK, code line 107 in https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_def.h)
To get the UART status use i.e.
HAL_UART_StateTypeDef UARTStatus;
UARTStatus = HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
The definition of HAL_UART_StateTypeDef is
typedef enum
{
HAL_UART_STATE_RESET = 0x00, /*!< Peripheral is not yet Initialized */
HAL_UART_STATE_READY = 0x01, /*!< Peripheral Initialized and ready for use */
HAL_UART_STATE_BUSY = 0x02, /*!< an internal process is ongoing */
HAL_UART_STATE_BUSY_TX = 0x12, /*!< Data Transmission process is ongoing */
HAL_UART_STATE_BUSY_RX = 0x22, /*!< Data Reception process is ongoing */
HAL_UART_STATE_BUSY_TX_RX = 0x32, /*!< Data Transmission and Reception process is ongoing */
HAL_UART_STATE_TIMEOUT = 0x03, /*!< Timeout state */
HAL_UART_STATE_ERROR = 0x04 /*!< Error */
}HAL_UART_StateTypeDef;
(https://github.com/synthetos/Motate/blob/master/MotateProject/motate/cmsis/TARGET_STM/TARGET_DISCO_F407VG/stm32f4xx_hal_uart.h code line 97)
The definition of HAL_StatusTypeDef (general HAL status) is
typedef enum
{
HAL_OK = 0x00,
HAL_ERROR = 0x01,
HAL_BUSY = 0x02,
HAL_TIMEOUT = 0x03
} HAL_StatusTypeDef;
You can print the HAL status (i.e. with UART transmit or SWO ITM_SendChar((*ptr++));, see https://ralimtek.com/stm32_debugging/ )
The HAL has its own reference manual, the HAL status is described in the reference manual https://www.st.com/content/ccc/resource/technical/document/user_manual/2f/71/ba/b8/75/54/47/cf/DM00105879.pdf/files/DM00105879.pdf/jcr:content/translations/en.DM00105879.pdf on page 54 in chapter 2.9 HAL common resources.
Debugging techniques are described in https://www.st.com/content/ccc/resource/technical/document/application_note/group0/3d/a5/0e/30/76/51/45/58/DM00354244/files/DM00354244.pdf/jcr:content/translations/en.DM00354244.pdf, also for your programming adapter, that you can directly integrate in CubeMX (i use Atollic with integrated CubeMX because Atollic is based on Eclipse IDE and is almost identical to use)
Another debugging tutorial is https://ardupilot.org/dev/docs/debugging-with-gdb-on-stm32.html (if you are on linux).
This could also be a race condition either of the HAL or the OS. The problem that i have is that you do not post your full code, especially not concerning your OS and this is possibly critical here
So maybe first check the HAL status and then focus on the OS part (race conditions, buffer, stack or heap overflow, ... https://www.st.com/content/ccc/resource/technical/document/user_manual/2d/60/ff/15/8c/c9/43/77/DM00105262.pdf/files/DM00105262.pdf/jcr:content/translations/en.DM00105262.pdf)
Stack overflows are always critical on embedded systems so here is links https://barrgroup.com/embedded-systems/how-to/prevent-detect-stack-overflow , https://www.iar.com/support/resources/articles/detecting-and-avoiding-stack-overflow-in-embedded-systems/
Also see Uart dma receive interrupt stops receiving data after several minutes and UART receive interrupt stops triggering after several hours of successful receive
Many developers avoid using the HAL because it is a bit buggy and not very transparent, i personally would also not use it when i want full control over the system behavior

LPC2148 UART interrupt

I am using LPC2148 with SIM800L on UART1 using interrupt. When I use memset(buff, 0 , sizeof(buff)); in while(1) at first the program works fine but when while(1) loop runs again it prints error over and over but when I comment the memset(buff, 0, sizeof(buff)); it works fine.
So why it is not receiving the data on using memset function?
#include <lpc214x.h>
#include <stdio.h>
#include <string.h>
__irq void uart1_interrupt(void);
void init_uart1(void); //////initialize uart1
void uart1_write(char data); //////send char on uart1
void uart1_send_string(char *str);//////send string on uart1
void Uart0_string(char *str); //////send string on uart0
void U0write(char data); //////send
char on uart0
void init_uart0(void); //////initialize uart0
void pll_init(void);
void timer_init(void);
void delay_ms(unsigned int ms);
//void clear_data(); /////clear buffer
char buff[160];
//char sms_receive[60];
int i, a = 0;
int main(void)
{
pll_init();
timer_init();
init_uart0();
//init_uart1();
VICVectAddr0 = (unsigned) uart1_interrupt; /////attach interrupt routine
VICVectCntl0 = (1<<5)|7; ////enable uart irq slot for uart1
VICIntEnable |= (1<<7); ////enable uart1 interrupt
VICIntSelect = 0x00000000;
init_uart1();
Uart0_string("gsm test\r\n");
delay_ms(3000);
while(1)
{
uart1_send_string("AT\r\n");
delay_ms(400);
if(strstr(buff,"OK"))
{
Uart0_string(buff);
}
else
{
Uart0_string("ERROR ");
}
delay_ms(3000);
uart1_send_string("AT+CNMI=?\r\n");
delay_ms(400);
if(strstr(buff,"+CNMI"))
{
Uart0_string(buff);
}
else
{
Uart0_string("ERROR ");
}
delay_ms(3000);
//clear_data();
memset(buff, 0 , sizeof(buff));
}
}
/*void clear_data()
{
for(i = 0; i<=sizeof(buff); i++)
{
buff[i] = 0;
}
}*/
__irq void uart1_interrupt(void)
{
buff[a] = U1RBR;
a++;
VICVectAddr = 0x00;
}
void init_uart1(void)
{
PINSEL0 = PINSEL0 | 0x00050000; ////UART1 pin selection
U1LCR = 0x83; ////8 bit, no parity, 1 stop bit, DLAB - 1
U1DLL = 0x56; ////86 in decimal
U1DLM = 0x00;
U1FDR = 0xF2;
U1LCR &= 0x0f; /////setting DLAB bit to 0
U1IER = 0x01; ////enable interrupt
}
void uart1_write(char data)
{
U1IER = 0x00;
while(!(U1LSR &(1<<5))); ////U1LSR contains THRE status bit, wait while THR is empty
U1THR = data;
U1IER = 0x01;
}
void uart1_send_string(char *str)
{
U1IER = 0x00;
while(*str != '\0')
{
uart1_write(*str++);
}
U1IER = 0x01;
}
/*char uart1_receive()
{
while(!(U1LSR & (1<<0)));
return U1RBR;
}*/
void init_uart0()
{
PINSEL0 = 0x00000005; ////selects TxD P0.0 and RxD P0.1
U0LCR = 0x83; ////8 bit, no parity 1 stop bit, DLAB = 1
U0DLL = 0x56; //// 86 in decimal
U0DLM = 0x00;
U0FDR = 0xF2; ////MULVAL and DIVADDVAL values
U0LCR &= 0x0F;
}
void U0write(char data)
{
while(!(U0LSR & (1<<5))); ///////wait till THR is not empty
U0THR = data; /////// write data to Transmit in U0THR
}
void Uart0_string(char *str)
{
while(*str != '\0')
{
U0write(*str++);
}
}
void pll_init(void)
{
PLL0CON = 0x01; /////enable PLL////
PLL0CFG = 0x24; /////configure PLL/////
PLL0FEED = 0xAA; //////feed sequence/////
PLL0FEED = 0x55; //////feed sequence/////
while(!(PLL0STAT & 0x00000400)); ///is locked////
PLL0CON = 0x03; ////connect PLL////
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
//VPBDIV = 0x01; /////// PCLK = CCLK = 60MHz
VPBDIV = 0x00; /////// PCLK = 60/4 = 15MHz
}
void timer_init(void)
{
//T0TCR = 0x00;
T0CTCR = 0x0; ////selection of timer mode with every rising pclk edge
T0PR = 14999; ////prescale register value will generate 1 ms at 60MHz
T0TCR = 0x02; ////reset the timer counter and prescale couter
}
void delay_ms(unsigned int ms)
{
//T0TC = 0x00000000;
T0TCR = 0x02; /////reset timer. Timer should be reset
T0TCR = 0x01; /////enable timer to generate delay
T0MR0 = ms;
while(T0TC < T0MR0); /////wait until Timer counter register reaches desired delay
T0TCR = 0x00; /////disable timer
}
output when using memset(buff, 0, sizeof(buff))
gsm test
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
ERROR ERROR ERROR ERROR
output when not using memset(buff, 0 , sizeof(buff)). I want to achive this output using memset(buff, 0 , sizeof(buff))
gsm test
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
a is reset only once at the start. The interrupt increments a on every character. When your main loop repeats, the ISR (interrupt service routine) will increment it further, finally overwriting the memory after buf.
That's why without memset() you get ever repeating the same result. The contents of buf is always checked from its beginning, but the received answers are stored one after the other.
Reset a on every entry in the loop, that should help.
However, writing (and/or reading) to the same variable from more than one thread is calling for disaster. Look for some lessons about multi-threaded programming. Yes, using interrupts is programming with multiple threads.
The while(1) loop in the main function does not make any input to char buff[160]. That is done only in the interrupt handler. So when you use memset to fill the buffer, it then begins with the string terminator character '\0' and the statements
if(strstr(buff,"OK"))
and
if(strstr(buff,"+CNMI"))
are false – NULL means no match was found – and so the error messages are output.
Note too that in the interrupt handler __irq void uart1_interrupt(void) you have
buff[a] = U1RBR;
a++;
but nowhere is a limited or reset or wrapped to prevent buffer overrun. So there is a disaster waiting to happen.

No response from UART

I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong?
#include <pic18f25k80.h>
#include "config.h"
#include <usart.h>
int i = 0;
unsigned char MessageBuffer[200];
void main() {
OSCCONbits.IRCF = 0b110; // 8MHz
TRISB6 = 0; // TX set as output
TRISB7 = 0; // RX set as output
// Clear TX interrupt
// Set RX interrupt
// 8-bit Asynch. mode
// BRGH = 1 = high baud mode
// 51 = ((8MHz/baud)/16)-1 with baud = 9600
Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE
& USART_EIGHT_BIT & USART_BRGH_HIGH, 51 );
RC2IF = 0; // reset RX2 flag
RC2IP = 0; // not high priority
RC2IE = 1; // Eneble RX2 interrupt
INTCONbits.PEIE = 1; // enable peripheral interrupts
INTCONbits.GIE = 1; // enable interrupts
RCSTA2bits.SPEN = 1; // enable USART
while(1){
}
}
void interrupt ISR () {
if(PIR3bits.RC2IF == 1) {
if(i<200) { // buffer size
MessageBuffer[i] = Read2USART(); // read byte from RX reg
if (MessageBuffer[i] == 0x0D) { // check for return key
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i=0;
return;
}
i++;
RC2IF = 0; // clear RX flag
} else {
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i = 0;
return;
}
}
}
I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive.
Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like:
void interrupt ISR () {
char data;
if(PIR3bits.RC2IF == 1) {
data = Read2USART(); // always read byte from RX reg (clears RC2IF)
if(i<200) { // buffer size
MessageBuffer[i] = data; // read byte from RX reg
i++;
}
else{
// flag buffer full error
}
}
}
and doing the rest of what you are doing in the while(1) loop.

Resources