at the beginning, I'm relatively new to the world of microcontroller programming.
I am preparing a program for stable communication between the STM32 and a PC equipped with Matlab. Currently I've managed to create a connection between Matlab and STM32 (F303RE board) but it works unstable. Communication was based on interruptions (both receiving and sending information). My code on STM32:
Main:
int main(void)
{
HAL_Init();
SystemClockConfig();
UART2_Init();
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
while (1)
{
Print_CAN_Frame("Tx", IPC_Ligths.ID, IPC_Ligths.DLC, IPC_Ligths.CAN_Tx);
HAL_Delay(3000);
/*
Section for handling incoming information by UART
while((flag_UART_RX_COMPLETED && flag_UART_TX_COMPLETED) == TRUE)
{
parseFromUART(data_buffer);
saveDataToFrame(canUartBuffer);
ClearArray(data_buffer, 70);
count = 0;
flag_UART_RX_COMPLETED = FALSE;
flag_UART_TX_COMPLETED = FALSE;
}
*/
}
return 0;
}
Callbacks
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (rcvd_data == '\r') {
data_buffer[count++] = '\r';
flag_UART_RX_COMPLETED = TRUE;
if (HAL_UART_Transmit_IT(&huart2, data_buffer, count) != HAL_OK)
{
Error_handler();
}
}
else
{
data_buffer[count++] = rcvd_data;
}
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
flag_UART_TX_COMPLETED = TRUE;
}
and interrupts hanlders:
void SysTick_Handler (void)
{
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
}
void USART2_IRQHandler (void)
{
HAL_UART_IRQHandler(&huart2);
}
The code from matlab.
Function to send data via UART (I want a nice CAN frame to show me on the serial port monitor)
function statusCode = CANsend(ID, DLC, BUFFER)
% Function to send CAN data by USART port to STM32.
% Data sended by this function will be avaiable via Serial Port Monitor
% ***** PARAMETERS *****
% ID - CAN frame identifier
% DLC - CAN frame data length code
% BUFFER - CAN frame data buffer(array) in HEX - f.e. [0xAA, 0xBB]
global serialPortConfiguration
flag = true;
UARTstring = ParseDataForUART(ID,DLC,BUFFER);
writeline(serialPortConfiguration,UARTstring);
% Check until STM32 give echo for given frame (frame accepted)
while flag
receivedData = readline(serialPortConfiguration);
if ( char(receivedData) == UARTstring)
flag = false;
statusCode = "Data Send Succeded";
disp(UARTstring);
pause(0.1)
else
pause(0.1)
writeline(serialPortConfiguration,UARTstring);
end
end
end
and function to configure communication via UART in Matlab:
function InitializeCommunication(portNumber,baudRate)
% Function to configure basic USART communication paramters
% portNumber: number of serial port (f.e: 'COM5', 'COM10')
% baudRate: baud rate for communication (default 115200)
% example: InitializeCommunication('COM10',115200)
global serialPortConfiguration
serialPortConfiguration = serialport(portNumber,baudRate);
configureTerminator(serialPortConfiguration,"CR");
end
What is this strange behavior? First of all, after sending several frames through the CANsend function in matlab (e.g. 15 - 20). the program stops into HAL_GetTick or I have UART Over-Run error. When I uncomment in the main function the part of the code responsible for handling incoming frames the program crash after sending the first message. Apart from sending data by Matlab I'm also sending data for debugging by TeraTerm and there everything seems to work much more stable (although not identical). Do you have any ideas what could be wrong? Maybe changing the approach and implementation by DMA will help?
Related
I'm trying to understand how the STM32F091VB manages the send of data via serial protocol with the function HAL_UART_Transmit_IT()
At the moment I've a function called in the main() that creates the packet and send it via serial; it is something like this:
tx1[0] = STX;
tx1[1] = 0xFF;
tx1[2] = 0x80;
tx1[3] = 0x80;
DE_TAST_HIGH;
HAL_UART_Transmit_IT(&huart3, tx1, 8);
Now, the data I'm sending is quite small so the code run pretty fast and I'm trying to understand what's going to happen if I try to send a huge packet via serial protocol.
For istance, if my tx1[] is 100byte the HAL_UART_Transmit_IT() function block the CPU waiting while the full packet is sent to the serial port or it works more like a separate process where I tell the micro to send that packet and, while sending it it also process the remaining part of my code/main function?
I've tried to search on the micro datasheet to see if there was something about this process but I had no luck. I've read the stm32f0xx_hal_uart.c and it confirms that it is sent via interrupt in a non blocking mode but I would like to have some more in depth documentation about it
First of all you need to understand how the HAL_UART_Transmit_IT is meant to be used. We can get some help from STM FAQ.
The function is "non blocking" because when you call it it will do some configuration of the interrupts and then return. The buffer will not be transmitted during the call to your function, instead the heavy lifting is deferred to a later stage.
We can further have a look at the source code, to get a proof from what I said (note I kept only the juicy parts).
Blocking
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t* tmp;
uint32_t tickstart = 0U;
// [ ... ]
huart->TxXferSize = Size;
huart->TxXferCount = Size;
while(huart->TxXferCount > 0U)
{
// [ ... ]
// This is were the actual HW regs are accessed, starting the transfer
huart->Instance->DR = (*pData++ & (uint8_t)0xFF);
}
}
// [ ... ]
return HAL_OK
}
Non Blocking
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
/* Enable the UART Transmit data register empty Interrupt */
// This is the only part were HW regs are accessed. What is happening here??
SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
return HAL_OK;
}
The _IT function only activates one interrupt, based also on the datasheet:
This means we will receive an interrupt whenever the TX buffer is free. Who is actually sending the data then?
With the help of the FAQs and reading the source code, we find that void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) does something like this:
/* UART in mode Transmitter ------------------------------------------------*/
if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
}
Which in turn calls the UART_Transmit_IT
static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
uint16_t* tmp;
/* Check that a Tx process is ongoing */
if(huart->gState == HAL_UART_STATE_BUSY_TX)
{
huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
if(--huart->TxXferCount == 0U)
{
/* Disable the UART Transmit Complete Interrupt */
CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
/* Enable the UART Transmit Complete Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
This function transmits only one byte! It then decrements the counter for the transmission (remember, all the information was set into the uart handler) and if it reaches 0, finally the complete interrupt is called.
Interrupts
Note that StmCube does the peripheral initialization and interrupt linking for you, but if you program from scratch you need to remember to write and register UART_IRQ_Handler
You can find here the code navigator to review my snippets and investigate further.
I am trying to receive multiple bytes over SPI. The aim is when the master starts the SPI transfer, slave MCU is interrupted, and it should read the data via SPI and store it in an array, which will be then used by my application for other operations such as determining the device ID and the contents of the packet.
void interrupt __high_priority my_isr_high(void) {
if (PIR1bits.SSP1IF) { // Interrupt from SPI?
rx[buffer_pointer] = SSP1BUF; // Get data from MSSP and store in RX buffer
buffer_pointer++; // Next data
if (buffer_pointer < FRAME_SIZE) // Ended?
SSP1BUF = tx[buffer_pointer]; // Send next byte to SPI
else
buffer_pointer = FRAME_SIZE;
PIR1bits.SSP1IF = 0; // Clear interrupt flag
}
}
However, I am not receiving the 3 bytes correctly. I am sending the following from the master:
dataPacket[0] = 0x43; // Decimal 67
dataPacket[1] = 0x42; //66
dataPacket[2] = 0x41; //65
While I am receiving as follows from the ISR():
rx[0]: 67
rx[1]: 65
rx[2]: 67
Am I missing something or handling the SPI incorrectly?
This will really solve the issue that I am stuck with and maybe will also help others who what to rx multiple bytes.
I am sharing my codes here so that it helps to find the solution quickly. Also included is a .zip file for compiling. Check the Codes here
So far the above code did not work for me properly. Therefore, after a little bit of digging online and other forums I found the following way to read multiple bytes:
uint8_t SPI_ExchangeHandler(uint8_t byte){
static uint8_t i = 0;
for(i=0; i<3; i++){
SSP1BUF =0x00;
while(!SSP1STATbits.BF);
rx_buff[i]=SSP1BUF;
}
State = SEND;
return byte;
}
Although the above codes give me what expected (i.e, correct data packets in the ordered manner), however, it misses two SPI interrupts every time and then displays/captures the correct data. Hence, two sets of data are always lost and then the third one is received correctly.
Is something wrongly configured or missing?
Finally, I managed to receive all the 3 bytes correctly. Sharing the codes below:
My interrupt service routine that triggers the MCU when master SPI has data to send.
void interrupt INTERRUPT_InterruptManager (void){
if(PIE1bits.SSP1IE == 1 && PIR1bits.SSP1IF == 1)
{
SPI_ISR();
}
}
The SPI_ISR code was autogenerated by the MCC GUI.
void SPI_ISR(void)
{
SSP1BUF = SPI_xchgHandler(SSP1BUF);
}
void SPI_setExchangeHandler(uint8_t (* InterruptHandler)(uint8_t))
{
SPI_xchgHandler = InterruptHandler;
}
Then I handle the SPI via a custom function using SPI_setExchangeHandler() as follows:
#define FRAME_SIZE 10 // Frame fixed size
volatile static uint8_t rx_buff[FRAME_SIZE]; //RX buffer
uint8_t SPI_ExchangeHandler(uint8_t byte)
{
static uint8_t i = 0;
rx_buff[i]=SSP1BUF;
i++;
if(i <= 2){
rx_buff[i]=SSP1BUF;
SSP1BUF = 0x00;
while(!SSP1STATbits.BF){};
i++;
}
else{
i = 2;
}
PIR1bits.SSP1IF = 0; // Clear the SPI interrupt flag
State = SEND;
return byte;
}
And I print out the values as follows for debugging:
printf("CMD:%d \n", rx_buff[0]);
printf("BUF1: %d \n", rx_buff[1]);
printf("BUF2: %d \n\n", rx_buff[2]);
However, I am pretty sure this is not the best/optimized way to handle multiple bytes from SPI, therefore, if there is an alternative, share...
I'm having trouble trying to connect my light sensor (MAX44009) with I2C. I will explain what I've done and I hope someone can help me.
I am connecting this connection card on HMI port of my XMC4400 with 80 ports.
I've connected the sensor according to this table.
SCA - pin37
SCL - pin38
GND - pin 80
3.3 - pin 3.3V of XMC4400
Then I've tried to adapt the I2C Master example (available on DAVE tutorials) for my light sensor. I've created an I2C master app with the following settings:
My main.c is this:
Code:
#include <DAVE.h>
#define IO_EXPANDER_ADDRESS (0x4A)
uint8_t tx_buffer[4] = {0x00,0x01,0x02,0x03};
volatile uint8_t tx_completion_0 = 0;
volatile uint8_t rx_completion_0 = 0;
/* Transmit callback handling */
void tx_callback_0(void)
{
tx_completion_0 = 1;
}
/* Receive callback handling */
void rx_callback_0(void)
{
rx_completion_0 = 1;
}
/* Delay */
void delay(uint32_t counter)
{
volatile uint32_t cnt = counter;
while(--cnt);
}
/*
* For this demo the HMI satellite board for the XMC45 CPU board is required.
* It communicates with the IO expander (U360: PCA9502) found in the mentioned satellite board.
* The demo implements a binary counter using the LEDs attached to the IO expander.
*
*/
int main(void)
{
DAVE_Init();
uint8_t received_data;
uint8_t counter = 0;
/* Write data to reset the LEDs through the IO EXPANDER: DIR and 0xFF */
I2C_MASTER_Transmit(&I2C_MASTER_0,true,IO_EXPANDER_ADDRESS,&tx_buffer[1],2,false);
while(tx_completion_0 == 0);
tx_completion_0 = 0;
while(counter < 255)
{
tx_buffer[3] = ~counter;
counter++;
/* Write data to set the STATE of the IO EXPANDER */
I2C_MASTER_Transmit(&I2C_MASTER_0,true,IO_EXPANDER_ADDRESS,&tx_buffer[3],2,false);
while(tx_completion_0 == 0){
tx_callback_0();
}
tx_completion_0 = 0;
/* Receive the data from the IO EXPANDER */
I2C_MASTER_Receive(&I2C_MASTER_0,true,IO_EXPANDER_ADDRESS,&received_data,2,true,true);
printf("%d", received_data);
while(rx_completion_0 == 0){
rx_callback_0();
}
rx_completion_0 = 0;
/* Check if the received data is correct*/
if(tx_buffer[3] != received_data)
{
// while(1);
}
/* Delay to make visible the change */
delay(0xfffff);
}
while(1);
return 0;
}
I think my callback functions are not working, since it stops every time I execute one I2C function. on this case is on line 108. Plus, sometimes it gives me an error/warning:
No source available on 0x00.
import smbus
import time
# Get I2C bus
bus = smbus.SMBus(1)
# MAX44009 address, 0x4A(74)
# Select configuration register, 0x02(02)
# 0x40(64) Continuous mode, Integration time = 800 ms
bus.write_byte_data(0x4A, 0x02, 0x40)
time.sleep(0.5)
# MAX44009 address, 0x4A(74)
# Read data back from 0x03(03), 2 bytes
# luminance MSB, luminance LSB
data = bus.read_i2c_block_data(0x4A, 0x03, 2)
# Convert the data to lux
exponent = (data[0] & 0xF0) >> 4
mantissa = ((data[0] & 0x0F) << 4) | (data[1] & 0x0F)
luminance = ((2 ** exponent) * mantissa) * 0.045
# Output data to screen
print "Ambient Light luminance : %.2f lux" %luminance
I have this Python code that works fine on my sensor light when I'm using raspberry pi, I've tried to do the same thing on XMC but without success. I hope you can help me.
First of all I would recommend to build a if statement arround your code
like
DAVE_STATUS_t init_status;
init_status = DAVE_Init();
if(init_status == DAVE_STATUS_SUCCESS)
{
... code
}
With this you can check if the DAVE APP is initialized correct. If it is the case you can look further into the callback issue. If not it's a problem with the configuration.
You can find further code exampels by rightlciking on the I2C Master field in teh APP Dependency window -> APP Help. There are examples for the methods provided by the APP.
I'm using hal can library for stm32L476vg mcu. I'm debugging my can transmission app and I can observe something apparently wrong in HAL_CAN_Transmit() sequence execution and its returned value, specially when it musts return HAL_TIMEOUT value.
Main code:
#include "main.h"
#include "Pm03_SystemConfig.h"
#include "App_Task_CAN.h"
uint8_t charBuffer[10]={0x00};
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
Pm03_SystemClock_Config();
App_Task_CAN_reset();
App_Task_CAN_init();
charBuffer[0]=0xCA;
charBuffer[1]=0xFE;
while (1)
{
App_Task_CAN_sendData(&charBuffer[0]);
}
}
My TX higher level function implementation that calls hal_can transmit and init for can configuration in App_Task_CAN.c file:
uint8_t App_Task_CAN_sendData(uint8_t* cBuffer)
{
for (uint8_t index=0; index< DATABTXLONG; index ++)
{
HCAN_Struct.pTxMsg->Data[index]= cBuffer[index];
}
if (HAL_CAN_Transmit(&HCAN_Struct, TIMEOUT)!=HAL_OK)
{
TaskCan_Error_Handler();
}
}
void App_Task_CAN_init(void)
{
static CanTxMsgTypeDef TxMessage;
static CanRxMsgTypeDef RxMessage;
/*configuracion timing para obtener 500kb/s*/
HCAN_Struct.Instance = CAN1;
HCAN_Struct.pTxMsg = &TxMessage;
HCAN_Struct.pRxMsg = &RxMessage;
HCAN_Struct.Init.Prescaler = 1;
HCAN_Struct.Init.Mode = CAN_MODE_NORMAL;//values defined in different hal libraries
HCAN_Struct.Init.SJW = CAN_SJW_1TQ;
HCAN_Struct.Init.BS1 = CAN_BS1_6TQ;//segment point at 87.5%
HCAN_Struct.Init.BS2 = CAN_BS2_1TQ;
HCAN_Struct.Init.TTCM = DISABLE;
HCAN_Struct.Init.ABOM = DISABLE;
HCAN_Struct.Init.AWUM = DISABLE;
HCAN_Struct.Init.NART = DISABLE;
HCAN_Struct.Init.RFLM = DISABLE;//Fifo locked mode disabled
HCAN_Struct.Init.TXFP = DISABLE;//prioridad de tx por id (más bajo más prioridad)
if (HAL_CAN_Init(&HCAN_Struct) != HAL_OK)
{
TaskCan_Error_Handler();
}
//TX
HCAN_Struct.pTxMsg->StdId = 0x321;
HCAN_Struct.pTxMsg->ExtId = 0x01;//29 bits
HCAN_Struct.pTxMsg->IDE = CAN_ID_STD;//values defined in different hal libraries
HCAN_Struct.pTxMsg->RTR = CAN_RTR_DATA;//values defined in different hal libraries
HCAN_Struct.pTxMsg->DLC = DATABTXLONG;//1-9
}
some defines used above, declared in App_Task_CAN.h:
/* Timeout for can operations in bit time units */
#define TIMEOUT 100
/* param for config mesg frames */
#define DATABTXLONG 2
I was debugging and going step by step through all the hal transmit function sequence (concerned piece of code below) and I can see how, after first TXRQ ->
Part of hal_can_transmit function in stm32l4xx_hal_can.c file:
HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
{
...
/* Request transmission */
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;
...
/* Check End of transmission flag */
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Process unlocked */
__HAL_UNLOCK(hcan);//line in which thread breaks
return HAL_TIMEOUT;//ignored line during debug
}
}
}
...
}
(NOTE: This next piece of code belongs to hal library provided by ST)
-> once the thread passes through the above transmit call, after TXRQ line this happens:
the thread waits for end Tx flag and
after timeout value expires, the threads goes into timeout state line
it arrives until hal unlock() macro line
after this, it exits/breaks the execution and returns to the line where this function was called ignoring the next line "return HAL_TIMEOUT".
The thread is broken just before arriving to this line (red text line). It returns to my transmit call a HAL_OK value! I recieve HAL_OK value! I confirm this after mounting a switch case in order to see what value it was reciving instead of HAL_TIMEOUT.
It happens from the first time transmit is called. I don't know if it is normal behavior. Obviously it is a hal_can code fact and I can not do anything from code user to fix it.
Has someone else, who worked with hal can for stm32, faced this situation?
My Tx does not work and I was looking for the possible fail causes through debugging. Hence I have seen this. Maybe there is more than this code problem to solve. But I think my code is very simple to fail: I only call send data in a infinite loop (of course after can init). By debugging I can see how data is arriving to the mailboxes correctly, but flag of TXOk never sets.
So, maybe this hal_can strange behavior is part of the cause of my transmission fail.
It seems to be a third party bug. Has someone deal with same situation? Any suggestion about my user code? is there something to improve?
I am trying to write a device code for C8051F340 to get the data from the host(PC) via USB. I have some example from silicon lab and the code look like below:
void Receive_File(void)
{
ReadStageLength = ((BytesToRead - BytesRead) > MAX_BLOCK_SIZE_READ)? MAX_BLOCK_SIZE_READ:(BytesToRead - BytesRead);
BytesRead += Block_Read((U8*)(&TempStorage[BlockIndex]), ReadStageLength); // Read Block
BlockIndex++;
// If device has received as many bytes as fit on one FLASH page, disable interrupts,
// write page to flash, reset packet index, enable interrupts
// Send handshake packet 0xFF to host after FLASH write
if ((BlockIndex == (BLOCKS_PR_PAGE)) || (BytesRead == BytesToRead))
{
Page_Erase((U8*)(PageIndices[PageIndex]));
Page_Write((U8*)(PageIndices[PageIndex]));
PageIndex++;
Led1 = !Led1;
BlockIndex = 0;
Buffer[0] = 0xFF;
Block_Write(Buffer, 1); // Send handshake Acknowledge to host
}
// Go to Idle state if last packet has been received
if (BytesRead == BytesToRead) {M_State = ST_IDLE_DEV; Led1 = 0;}
}
// Startup code for SDCC to disablt WDT before initializing variables so that
// a reset does not occur
#if defined SDCC
void _sdcc_external_startup (void)
{
PCA0MD &= ~0x40; // Disable Watchdog timer
}
#endif
I have some questions want to ask:
1. Where the data goes? the Buffer [0]?
2. if I got a Hex value transfer from the host, can I just read the Buffer [0] to get it ?
sorry I am a newbie.
Thank you.
Your received data stored in array TempStorage
You used Buufer[0] (the value 0xFF) for to send data to host