函数指针正在改变自己的地址
The function pointer is changing its own address
我是第一次使用函数指针,运行遇到了一个奇怪的问题。我正在为 STM32G4xx 编写代码。主要思路是通过LPUART进行t运行发送和接收数据。我已经实现了简单的 FSM 来处理 TX 和 RX。 LPUART 配置为 DMA 中断模式。我对函数指针进行了 typedef 并在 main.h 文件中声明了三个函数指针变量(ISR 句柄)如下:
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* USER CODE BEGIN ET */
typedef void (*_func_clbck)(void);
/* USER CODE END ET */
_func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback;
_func_clbck lpuart_dma_tx_tc_isr_clback;
_func_clbck lpuart_dma_rx_tc_isr_clback;
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
函数指针的定义在main.c文件中的函数MX_LPUART1_UART_Init()
中。
#include "main.h"
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
/** Configure the internal voltage reference buffer voltage scale
*/
LL_VREFBUF_SetVoltageScaling(LL_VREFBUF_VOLTAGE_SCALE1);
/** Enable the Internal Voltage Reference buffer
*/
LL_VREFBUF_Enable();
/** Configure the internal voltage reference buffer high impedance mode
*/
LL_VREFBUF_DisableHIZ();
/** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
*/
LL_PWR_DisableUCPDDeadBattery();
/* 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_LPUART1_UART_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
#ifdef LPUART_TEST
lpuart_init_test();
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_6);
//LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_6);
LL_mDelay(1);
uint8_t buf[9] ={'a','d','v',' ','l','o','w','\r','\n'};
//uint8_t buf[9] ={1,2,3,4,5,6,7,8,9};
#ifdef LPUART_TEST
uint16_t len_test[19] = {0,16,17,65535, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for(uint16_t i = 0 ; i<19 ; i++){
set_len_rx_dma_buff(len_test[i]);
lpuart_rx_test();
}
#endif
static uint8_t once = 1;
while (1)
{
lpuart_task();
//delay_ms_DWT(1);
/*if(once){
once = 0;
lpuart_start_tx(buf, 9);
LL_mDelay(100);
}*/
if(1){
//lpuart_start_tx(buf, 9);
if(!lpuart_isTxBusy()){
lpuart_start_tx(buf, 9);
delay_ms_DWT(1);
if(!lpuart_isRxBusy()){
rxOldIndex += rxIndex;
if(rxOldIndex > 255){
rxOldIndex = 0;
rxIndex = 0;
}
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
}
}
}
}
//}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
static void MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**LPUART1 GPIO Configuration
PB10 ------> LPUART1_RX
PB11 ------> LPUART1_TX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART1_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_LPUART1_TX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1_RX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_LPUART1_RX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1 interrupt Init */
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(LPUART1_IRQn);
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
LPUART_InitStruct.BaudRate = 9600;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_DisableFIFO(LPUART1);
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_SWAPPED);
// LL_LPUART_EnableOverrunDetect(LPUART1);
// LL_LPUART_EnableDMADeactOnRxErr(LPUART1);
/* USER CODE BEGIN WKUPType LPUART1 */
/* USER CODE END WKUPType LPUART1 */
LL_LPUART_Enable(LPUART1);
/* Polling LPUART1 initialisation */
while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1))))
{
}
/* USER CODE BEGIN LPUART1_Init 2 */
//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);
/* Enable TC interrupts for RX */
/* Enable HT & TC interrupts for TX */
// LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
lpuart_tx_tc_isr_clback = LPUART_TX_TC_ISR_CALLBACK;
//lpuart_rx_rne_isr_clback = &LPUART_RX_RXNE_ISR_CALLBACK;
lpuart_dma_tx_tc_isr_clback = LPUART_DMA_TX_TC_CALLBACK;
lpuart_dma_rx_tc_isr_clback = LPUART_DMA_RX_TC_CALLBACK;
//LL_LPUART_EnableDirectionRx(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
//LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
/* USER CODE END LPUART1_Init 2 */
}
在 main 函数中,在 while 循环中,我在 if(!lpuart_isTxBusy())
语句 之后 调用 lpuart_start_tx(buf, 9);
函数。这会导致函数指针的地址发生变化 lpuart_dma_rx_tc_isr_clback
但其他两个函数指针不会改变其地址并且可以正常工作。当在接收数据时引发中断时,它会尝试执行 lpuart_dma_rx_tc_isr_clback
,这会导致硬故障,因为它的地址已被修改。请注意,如果我在 lpuart_start_tx(buf, 9);
之前调用 if(!lpuart_isTxBusy())
,那么一切正常。我不明白这可能是什么问题。
我检查了 CFSR
寄存器,每次都出现了不同的标志。我注意到在 IBUSERR
、IACCVOIL
和 INVSTATE
三个标志中,其中一个被举起。我没有包含完整的 main.c 文件。
LPUART FSM实现如下:
lpuart.h 文件
#ifndef INC_LPUART_H_
#define INC_LPUART_H_
#include "ring_buffer.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len );
uint8_t LPUART_isTxFinished(void);
void LPUART_clear_tx_finishedFlag();
uint8_t lpuart_isRxBusy(void);
uint8_t lpuart_isTxBusy(void);
void lpuart_task();
void LPUART_TX_TC_ISR_CALLBACK(void);
void LPUART_DMA_TX_TC_CALLBACK(void);
void LPUART_DMA_RX_TC_CALLBACK(void);
#endif /* INC_LPUART_H_ */
lpuart.c
#include "lpuart.h"
#include "string.h"
#include "stm32g4xx_ll_lpuart.h"
#include "stm32g4xx_ll_dma.h"
#define SIZE_TX_BUFF 256
#define SIZE_RX_BUFF 256
#define SIZE_DMA_RX_BUFF 64
static uint8_t rxBuf[SIZE_RX_BUFF];
static uint8_t rxDMA_Buf[SIZE_DMA_RX_BUFF];
static uint8_t txBuf[SIZE_TX_BUFF];
RingBuffer lpuart_RX_ring_buff;
static uint8_t* tempTxBuf;
static uint16_t txLen = 0;
static void setTxDataLengthDMA(uint16_t len);
static void lpuart_transmit();
static void lpuart_finished_tx();
static void no_action();
static void lpuart_rx();
static void check_rx_dma_buff();
static uint8_t ev_no_event(void);
static uint8_t ev_txtc(void);
static uint8_t ev_start_tx(void);
static uint8_t ev_dmatxtc(void);
static uint8_t ev_rx_read(void);
static uint8_t ev_buff_full(void);
typedef uint8_t (*t_event_func)(void);
typedef void(*t_action_func)(void);
typedef struct{
uint16_t txtc:1;
uint16_t tx_busy:1;
uint16_t dmatxtc:1;
uint16_t dmarxtc:1;
uint16_t start_tx:1;
uint16_t rx_read:1;
uint16_t buff_full:1;
uint16_t is_fsm_table_init:1;
uint16_t ext_rxBusyFlag:1;
}t_event;
typedef enum {INIT, READY, BUSY, COMPLETE, LPUART_ERROR}t_state;
typedef struct{
t_state present_state;
t_event_func event1;
t_event_func event2;
t_action_func action1;
t_action_func action2;
t_state next_state;
}t_fsm_row;
typedef struct{
t_state current_state;
t_state previous_state;
t_fsm_row stt_row[7];
uint16_t number_of_rows;
}t_fsm_table;
t_event lpuart_event;
uint8_t lpuart_isTxBusy(void){
return lpuart_event.tx_busy;
}
uint8_t lpuart_isRxBusy(){
return lpuart_event.ext_rxBusyFlag;
}
uint8_t ev_no_event(void){
return 1;
}
uint8_t ev_txtc(void){
return lpuart_event.txtc;
}
uint8_t ev_start_tx(void){
return lpuart_event.start_tx;
}
uint8_t ev_dmatxtc(void){
return lpuart_event.dmatxtc;
}
uint8_t ev_rx_read(void){
return lpuart_event.rx_read || lpuart_event.dmarxtc;
}
uint8_t ev_buff_full(void){
return lpuart_event.buff_full;
}
void no_action(){
return;
}
void lpuart_init(void){
memset(rxBuf, 0, (size_t)SIZE_RX_BUFF );
memset(rxDMA_Buf, 0, (size_t)SIZE_DMA_RX_BUFF );
memset(txBuf, 0, (size_t)SIZE_TX_BUFF );
RingBuffer_init(&lpuart_RX_ring_buff,rxBuf , (uint16_t)SIZE_RX_BUFF);
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
LL_LPUART_DisableDirectionRx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
/*TX buffer address attached to DMA channel1 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
(uint32_t)txBuf,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_TRANSMIT),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, SIZE_TX_BUFF);
/*RX buffer address attached to DMA channel2 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_RECEIVE),
(uint32_t)rxDMA_Buf,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, SIZE_DMA_RX_BUFF);
LL_LPUART_EnableDMAReq_RX(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
LL_LPUART_EnableDirectionRx(LPUART1);
lpuart_event.tx_busy = 0;
}
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len ){
if(!lpuart_event.tx_busy){
lpuart_event.tx_busy = 1;
if(len < SIZE_TX_BUFF){
lpuart_event.start_tx = 1;
tempTxBuf = buff;
txLen = len;
}else{
/* lpuart_event.start_tx = 0;
lpuart_event.buff_full = 1;*/
return 0;
}
return 1;
}else{
return 0;
}
}
void lpuart_transmit(){
memcpy(txBuf, tempTxBuf, txLen);
setTxDataLengthDMA(txLen);
LL_LPUART_EnableDMAReq_TX(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
LL_LPUART_EnableIT_TC(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
}
void lpuart_finished_tx(){
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
lpuart_event.txtc = 0;
lpuart_event.dmatxtc = 0;
lpuart_event.start_tx = 0;
lpuart_event.tx_busy = 0;
}
void setTxDataLengthDMA(uint16_t len){
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
/* Clear all flags */
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_TE1(DMA1);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, len);
}
void check_rx_dma_buff(){
static uint16_t old_len = SIZE_DMA_RX_BUFF;
uint16_t current_len = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(old_len != current_len ){
if(current_len > 0){
lpuart_event.rx_read = 1;
}
}
old_len = current_len;
}
static uint16_t old_pos = 0;
uint16_t pos = 0;
void lpuart_rx(){
lpuart_event.ext_rxBusyFlag = 1;
if(lpuart_event.dmarxtc){
lpuart_event.dmarxtc = 0;
}
if(lpuart_event.rx_read){
lpuart_event.rx_read = 0;
}
pos = (uint16_t)SIZE_DMA_RX_BUFF - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(pos > SIZE_DMA_RX_BUFF ){
pos = SIZE_DMA_RX_BUFF;
}
if(pos != old_pos /* || (pos == 0 && old_pos == 0)*/){
if (pos > old_pos) {
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],(pos - old_pos));
}else{
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],((uint16_t)SIZE_DMA_RX_BUFF - old_pos));
if(pos > 0){
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[0],pos);
}
}
}
old_pos = pos;
lpuart_event.ext_rxBusyFlag = 0;
}
t_fsm_row rowInit = {INIT,ev_no_event, ev_no_event, lpuart_init, no_action, READY };
t_fsm_row rowReady = {READY,ev_start_tx, ev_no_event, lpuart_transmit, no_action, BUSY };
t_fsm_row rowBusy = {BUSY,ev_dmatxtc, ev_txtc, lpuart_finished_tx, no_action, READY};
t_fsm_table lpuart_fsm_table = {INIT,INIT, {}};
void fsm_table_init(){
lpuart_fsm_table.current_state = INIT;
lpuart_fsm_table.stt_row[0] = rowInit;
lpuart_fsm_table.stt_row[1] = rowReady;
lpuart_fsm_table.stt_row[2] = rowBusy;
lpuart_event.is_fsm_table_init = 1;
lpuart_fsm_table.number_of_rows = 3;
}
void lpuar_tx_fsm(){
uint8_t ev = 0;
for(uint16_t rowIndex = 0; rowIndex < lpuart_fsm_table.number_of_rows; rowIndex++){
if(lpuart_fsm_table.current_state == lpuart_fsm_table.stt_row[rowIndex].present_state){
ev = lpuart_fsm_table.stt_row[rowIndex].event1() && lpuart_fsm_table.stt_row[rowIndex].event2();
if(ev){
lpuart_fsm_table.stt_row[rowIndex].action1();
lpuart_fsm_table.stt_row[rowIndex].action2();
lpuart_fsm_table.current_state = lpuart_fsm_table.stt_row[rowIndex].next_state;
lpuart_fsm_table.previous_state = lpuart_fsm_table.stt_row[rowIndex].present_state;
}
}
}
}
void lpuar_read_task(){
check_rx_dma_buff();
if(ev_rx_read()){
lpuart_rx();
}
}
void lpuart_task(){
if(!lpuart_event.is_fsm_table_init){
fsm_table_init();
}
//else{
lpuar_tx_fsm();
lpuar_read_task();
//}
}
void LPUART_TX_TC_ISR_CALLBACK(void){
lpuart_event.txtc = 1;
LL_LPUART_ClearFlag_TC(LPUART1);
}
void LPUART_DMA_TX_TC_CALLBACK(void){
lpuart_event.dmatxtc = 1;
LL_DMA_ClearFlag_TC1(DMA1);
}
void LPUART_DMA_RX_TC_CALLBACK(void){
if(LL_DMA_IsActiveFlag_TC2(DMA1)){
LL_DMA_ClearFlag_TC2(DMA1);
lpuart_event.dmarxtc = 1;
lpuart_rx();
}
if(LL_DMA_IsActiveFlag_TE2(DMA1)){
LL_DMA_ClearFlag_TE2(DMA1);
}
}
中断程序文件stm32g4xx_it.c:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32g4xx_it.h"
#include "lpuart.h"
extern _func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback = LPUART_RX_RXNE_ISR_CALLBACK;
extern _func_clbck lpuart_dma_tx_tc_isr_clback;
extern _func_clbck lpuart_dma_rx_tc_isr_clback;
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
void DMA1_Channel2_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
lpuart_dma_rx_tc_isr_clback();
//LPUART_DMA_RX_TC_CALLBACK();
/* USER CODE END DMA1_Channel2_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
/* USER CODE END DMA1_Channel2_IRQn 1 */
}
我在这里省略了一些代码。我确信我还没有完全理解函数指针是如何工作的。能否请您给我建议或解决方案。
我正在使用:
语言:C11
Compiler/build 工具:STM32 的 GNU 工具(7-2018-q2-更新)
IDE:STM32立方体IDE
如果您需要更多信息,请告诉我。提前致谢。
根据@Lundin 的建议,我在 lpuart_dma_rx_tc_isr_clback
函数指针变量上放置了一个观察点。它暴露了我的代码中的索引错误。该错误在 main.c.
中的 while 循环内
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
....
}
也有人指出函数指针变量不应该在flash中。
我是第一次使用函数指针,运行遇到了一个奇怪的问题。我正在为 STM32G4xx 编写代码。主要思路是通过LPUART进行t运行发送和接收数据。我已经实现了简单的 FSM 来处理 TX 和 RX。 LPUART 配置为 DMA 中断模式。我对函数指针进行了 typedef 并在 main.h 文件中声明了三个函数指针变量(ISR 句柄)如下:
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* USER CODE BEGIN ET */
typedef void (*_func_clbck)(void);
/* USER CODE END ET */
_func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback;
_func_clbck lpuart_dma_tx_tc_isr_clback;
_func_clbck lpuart_dma_rx_tc_isr_clback;
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
函数指针的定义在main.c文件中的函数MX_LPUART1_UART_Init()
中。
#include "main.h"
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
/** Configure the internal voltage reference buffer voltage scale
*/
LL_VREFBUF_SetVoltageScaling(LL_VREFBUF_VOLTAGE_SCALE1);
/** Enable the Internal Voltage Reference buffer
*/
LL_VREFBUF_Enable();
/** Configure the internal voltage reference buffer high impedance mode
*/
LL_VREFBUF_DisableHIZ();
/** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
*/
LL_PWR_DisableUCPDDeadBattery();
/* 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_LPUART1_UART_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
#ifdef LPUART_TEST
lpuart_init_test();
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_6);
//LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_6);
LL_mDelay(1);
uint8_t buf[9] ={'a','d','v',' ','l','o','w','\r','\n'};
//uint8_t buf[9] ={1,2,3,4,5,6,7,8,9};
#ifdef LPUART_TEST
uint16_t len_test[19] = {0,16,17,65535, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for(uint16_t i = 0 ; i<19 ; i++){
set_len_rx_dma_buff(len_test[i]);
lpuart_rx_test();
}
#endif
static uint8_t once = 1;
while (1)
{
lpuart_task();
//delay_ms_DWT(1);
/*if(once){
once = 0;
lpuart_start_tx(buf, 9);
LL_mDelay(100);
}*/
if(1){
//lpuart_start_tx(buf, 9);
if(!lpuart_isTxBusy()){
lpuart_start_tx(buf, 9);
delay_ms_DWT(1);
if(!lpuart_isRxBusy()){
rxOldIndex += rxIndex;
if(rxOldIndex > 255){
rxOldIndex = 0;
rxIndex = 0;
}
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
}
}
}
}
//}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
static void MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**LPUART1 GPIO Configuration
PB10 ------> LPUART1_RX
PB11 ------> LPUART1_TX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART1_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_LPUART1_TX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1_RX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_LPUART1_RX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1 interrupt Init */
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(LPUART1_IRQn);
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
LPUART_InitStruct.BaudRate = 9600;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_DisableFIFO(LPUART1);
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_SWAPPED);
// LL_LPUART_EnableOverrunDetect(LPUART1);
// LL_LPUART_EnableDMADeactOnRxErr(LPUART1);
/* USER CODE BEGIN WKUPType LPUART1 */
/* USER CODE END WKUPType LPUART1 */
LL_LPUART_Enable(LPUART1);
/* Polling LPUART1 initialisation */
while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1))))
{
}
/* USER CODE BEGIN LPUART1_Init 2 */
//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);
/* Enable TC interrupts for RX */
/* Enable HT & TC interrupts for TX */
// LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
lpuart_tx_tc_isr_clback = LPUART_TX_TC_ISR_CALLBACK;
//lpuart_rx_rne_isr_clback = &LPUART_RX_RXNE_ISR_CALLBACK;
lpuart_dma_tx_tc_isr_clback = LPUART_DMA_TX_TC_CALLBACK;
lpuart_dma_rx_tc_isr_clback = LPUART_DMA_RX_TC_CALLBACK;
//LL_LPUART_EnableDirectionRx(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
//LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
/* USER CODE END LPUART1_Init 2 */
}
在 main 函数中,在 while 循环中,我在 if(!lpuart_isTxBusy())
语句 之后 调用 lpuart_start_tx(buf, 9);
函数。这会导致函数指针的地址发生变化 lpuart_dma_rx_tc_isr_clback
但其他两个函数指针不会改变其地址并且可以正常工作。当在接收数据时引发中断时,它会尝试执行 lpuart_dma_rx_tc_isr_clback
,这会导致硬故障,因为它的地址已被修改。请注意,如果我在 lpuart_start_tx(buf, 9);
之前调用 if(!lpuart_isTxBusy())
,那么一切正常。我不明白这可能是什么问题。
我检查了 CFSR
寄存器,每次都出现了不同的标志。我注意到在 IBUSERR
、IACCVOIL
和 INVSTATE
三个标志中,其中一个被举起。我没有包含完整的 main.c 文件。
LPUART FSM实现如下: lpuart.h 文件
#ifndef INC_LPUART_H_
#define INC_LPUART_H_
#include "ring_buffer.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len );
uint8_t LPUART_isTxFinished(void);
void LPUART_clear_tx_finishedFlag();
uint8_t lpuart_isRxBusy(void);
uint8_t lpuart_isTxBusy(void);
void lpuart_task();
void LPUART_TX_TC_ISR_CALLBACK(void);
void LPUART_DMA_TX_TC_CALLBACK(void);
void LPUART_DMA_RX_TC_CALLBACK(void);
#endif /* INC_LPUART_H_ */
lpuart.c
#include "lpuart.h"
#include "string.h"
#include "stm32g4xx_ll_lpuart.h"
#include "stm32g4xx_ll_dma.h"
#define SIZE_TX_BUFF 256
#define SIZE_RX_BUFF 256
#define SIZE_DMA_RX_BUFF 64
static uint8_t rxBuf[SIZE_RX_BUFF];
static uint8_t rxDMA_Buf[SIZE_DMA_RX_BUFF];
static uint8_t txBuf[SIZE_TX_BUFF];
RingBuffer lpuart_RX_ring_buff;
static uint8_t* tempTxBuf;
static uint16_t txLen = 0;
static void setTxDataLengthDMA(uint16_t len);
static void lpuart_transmit();
static void lpuart_finished_tx();
static void no_action();
static void lpuart_rx();
static void check_rx_dma_buff();
static uint8_t ev_no_event(void);
static uint8_t ev_txtc(void);
static uint8_t ev_start_tx(void);
static uint8_t ev_dmatxtc(void);
static uint8_t ev_rx_read(void);
static uint8_t ev_buff_full(void);
typedef uint8_t (*t_event_func)(void);
typedef void(*t_action_func)(void);
typedef struct{
uint16_t txtc:1;
uint16_t tx_busy:1;
uint16_t dmatxtc:1;
uint16_t dmarxtc:1;
uint16_t start_tx:1;
uint16_t rx_read:1;
uint16_t buff_full:1;
uint16_t is_fsm_table_init:1;
uint16_t ext_rxBusyFlag:1;
}t_event;
typedef enum {INIT, READY, BUSY, COMPLETE, LPUART_ERROR}t_state;
typedef struct{
t_state present_state;
t_event_func event1;
t_event_func event2;
t_action_func action1;
t_action_func action2;
t_state next_state;
}t_fsm_row;
typedef struct{
t_state current_state;
t_state previous_state;
t_fsm_row stt_row[7];
uint16_t number_of_rows;
}t_fsm_table;
t_event lpuart_event;
uint8_t lpuart_isTxBusy(void){
return lpuart_event.tx_busy;
}
uint8_t lpuart_isRxBusy(){
return lpuart_event.ext_rxBusyFlag;
}
uint8_t ev_no_event(void){
return 1;
}
uint8_t ev_txtc(void){
return lpuart_event.txtc;
}
uint8_t ev_start_tx(void){
return lpuart_event.start_tx;
}
uint8_t ev_dmatxtc(void){
return lpuart_event.dmatxtc;
}
uint8_t ev_rx_read(void){
return lpuart_event.rx_read || lpuart_event.dmarxtc;
}
uint8_t ev_buff_full(void){
return lpuart_event.buff_full;
}
void no_action(){
return;
}
void lpuart_init(void){
memset(rxBuf, 0, (size_t)SIZE_RX_BUFF );
memset(rxDMA_Buf, 0, (size_t)SIZE_DMA_RX_BUFF );
memset(txBuf, 0, (size_t)SIZE_TX_BUFF );
RingBuffer_init(&lpuart_RX_ring_buff,rxBuf , (uint16_t)SIZE_RX_BUFF);
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
LL_LPUART_DisableDirectionRx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
/*TX buffer address attached to DMA channel1 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
(uint32_t)txBuf,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_TRANSMIT),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, SIZE_TX_BUFF);
/*RX buffer address attached to DMA channel2 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_RECEIVE),
(uint32_t)rxDMA_Buf,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, SIZE_DMA_RX_BUFF);
LL_LPUART_EnableDMAReq_RX(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
LL_LPUART_EnableDirectionRx(LPUART1);
lpuart_event.tx_busy = 0;
}
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len ){
if(!lpuart_event.tx_busy){
lpuart_event.tx_busy = 1;
if(len < SIZE_TX_BUFF){
lpuart_event.start_tx = 1;
tempTxBuf = buff;
txLen = len;
}else{
/* lpuart_event.start_tx = 0;
lpuart_event.buff_full = 1;*/
return 0;
}
return 1;
}else{
return 0;
}
}
void lpuart_transmit(){
memcpy(txBuf, tempTxBuf, txLen);
setTxDataLengthDMA(txLen);
LL_LPUART_EnableDMAReq_TX(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
LL_LPUART_EnableIT_TC(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
}
void lpuart_finished_tx(){
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
lpuart_event.txtc = 0;
lpuart_event.dmatxtc = 0;
lpuart_event.start_tx = 0;
lpuart_event.tx_busy = 0;
}
void setTxDataLengthDMA(uint16_t len){
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
/* Clear all flags */
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_TE1(DMA1);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, len);
}
void check_rx_dma_buff(){
static uint16_t old_len = SIZE_DMA_RX_BUFF;
uint16_t current_len = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(old_len != current_len ){
if(current_len > 0){
lpuart_event.rx_read = 1;
}
}
old_len = current_len;
}
static uint16_t old_pos = 0;
uint16_t pos = 0;
void lpuart_rx(){
lpuart_event.ext_rxBusyFlag = 1;
if(lpuart_event.dmarxtc){
lpuart_event.dmarxtc = 0;
}
if(lpuart_event.rx_read){
lpuart_event.rx_read = 0;
}
pos = (uint16_t)SIZE_DMA_RX_BUFF - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(pos > SIZE_DMA_RX_BUFF ){
pos = SIZE_DMA_RX_BUFF;
}
if(pos != old_pos /* || (pos == 0 && old_pos == 0)*/){
if (pos > old_pos) {
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],(pos - old_pos));
}else{
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],((uint16_t)SIZE_DMA_RX_BUFF - old_pos));
if(pos > 0){
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[0],pos);
}
}
}
old_pos = pos;
lpuart_event.ext_rxBusyFlag = 0;
}
t_fsm_row rowInit = {INIT,ev_no_event, ev_no_event, lpuart_init, no_action, READY };
t_fsm_row rowReady = {READY,ev_start_tx, ev_no_event, lpuart_transmit, no_action, BUSY };
t_fsm_row rowBusy = {BUSY,ev_dmatxtc, ev_txtc, lpuart_finished_tx, no_action, READY};
t_fsm_table lpuart_fsm_table = {INIT,INIT, {}};
void fsm_table_init(){
lpuart_fsm_table.current_state = INIT;
lpuart_fsm_table.stt_row[0] = rowInit;
lpuart_fsm_table.stt_row[1] = rowReady;
lpuart_fsm_table.stt_row[2] = rowBusy;
lpuart_event.is_fsm_table_init = 1;
lpuart_fsm_table.number_of_rows = 3;
}
void lpuar_tx_fsm(){
uint8_t ev = 0;
for(uint16_t rowIndex = 0; rowIndex < lpuart_fsm_table.number_of_rows; rowIndex++){
if(lpuart_fsm_table.current_state == lpuart_fsm_table.stt_row[rowIndex].present_state){
ev = lpuart_fsm_table.stt_row[rowIndex].event1() && lpuart_fsm_table.stt_row[rowIndex].event2();
if(ev){
lpuart_fsm_table.stt_row[rowIndex].action1();
lpuart_fsm_table.stt_row[rowIndex].action2();
lpuart_fsm_table.current_state = lpuart_fsm_table.stt_row[rowIndex].next_state;
lpuart_fsm_table.previous_state = lpuart_fsm_table.stt_row[rowIndex].present_state;
}
}
}
}
void lpuar_read_task(){
check_rx_dma_buff();
if(ev_rx_read()){
lpuart_rx();
}
}
void lpuart_task(){
if(!lpuart_event.is_fsm_table_init){
fsm_table_init();
}
//else{
lpuar_tx_fsm();
lpuar_read_task();
//}
}
void LPUART_TX_TC_ISR_CALLBACK(void){
lpuart_event.txtc = 1;
LL_LPUART_ClearFlag_TC(LPUART1);
}
void LPUART_DMA_TX_TC_CALLBACK(void){
lpuart_event.dmatxtc = 1;
LL_DMA_ClearFlag_TC1(DMA1);
}
void LPUART_DMA_RX_TC_CALLBACK(void){
if(LL_DMA_IsActiveFlag_TC2(DMA1)){
LL_DMA_ClearFlag_TC2(DMA1);
lpuart_event.dmarxtc = 1;
lpuart_rx();
}
if(LL_DMA_IsActiveFlag_TE2(DMA1)){
LL_DMA_ClearFlag_TE2(DMA1);
}
}
中断程序文件stm32g4xx_it.c:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32g4xx_it.h"
#include "lpuart.h"
extern _func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback = LPUART_RX_RXNE_ISR_CALLBACK;
extern _func_clbck lpuart_dma_tx_tc_isr_clback;
extern _func_clbck lpuart_dma_rx_tc_isr_clback;
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
void DMA1_Channel2_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
lpuart_dma_rx_tc_isr_clback();
//LPUART_DMA_RX_TC_CALLBACK();
/* USER CODE END DMA1_Channel2_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
/* USER CODE END DMA1_Channel2_IRQn 1 */
}
我在这里省略了一些代码。我确信我还没有完全理解函数指针是如何工作的。能否请您给我建议或解决方案。
我正在使用: 语言:C11 Compiler/build 工具:STM32 的 GNU 工具(7-2018-q2-更新) IDE:STM32立方体IDE
如果您需要更多信息,请告诉我。提前致谢。
根据@Lundin 的建议,我在 lpuart_dma_rx_tc_isr_clback
函数指针变量上放置了一个观察点。它暴露了我的代码中的索引错误。该错误在 main.c.
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
....
}
也有人指出函数指针变量不应该在flash中。