RS485 UART переделал на DMA по образцу HVD4

This commit is contained in:
Alexander Kurmis
2022-10-19 23:51:50 +03:00
parent e226faa454
commit 3803869521
12 changed files with 191 additions and 200 deletions

View File

@@ -13,6 +13,6 @@
#define REL_AUX_BIT (1u<<1)
void loop_iterate();
void timer1_ovf_isr(void);
#endif

View File

@@ -24,7 +24,7 @@ enum send_state {SEND_IDLE, SEND_BUSY};
void UART_RxCpltCallback(void);
void UART_TxCpltCallback(void);
void process_incoming_packet();
void modbus_loop_iterate();
uint8_t read_register(uint16_t address, uint16_t* value);
uint8_t write_register(uint16_t address, uint16_t value);

View File

@@ -51,6 +51,7 @@ void HardFault_Handler(void);
void SVC_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void DMA1_Channel2_3_IRQHandler(void);
void TIM1_BRK_UP_TRG_COM_IRQHandler(void);
void TIM1_CC_IRQHandler(void);
void USART1_IRQHandler(void);

View File

@@ -1,13 +0,0 @@
#ifndef __UART_H
#define __UART_H
#include <stdint.h>
#define RET_OK 0
#define RET_OVERFLOW 1
#define RET_TIMEOUT 2
uint8_t UART_Transmit_IT(uint8_t * data, uint16_t len, uint16_t timeout);
uint8_t UART_Receive_IT(uint8_t * data, uint16_t len, uint16_t timeout);
extern void UART_TxCpltCallback(void);
extern void UART_RxCpltCallback(void);
#endif

View File

@@ -47,6 +47,8 @@ TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
/* USER CODE BEGIN PV */
@@ -55,6 +57,7 @@ UART_HandleTypeDef huart1;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM1_Init(void);
@@ -95,11 +98,11 @@ int main(void)
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // включить прерывания usart'a
HAL_TIM_Base_Start_IT(&htim1);
/* USER CODE END 2 */
@@ -290,6 +293,22 @@ static void MX_USART1_UART_Init(void)
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel2_3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
}
/**
* @brief GPIO Initialization Function
* @param None

View File

@@ -6,11 +6,13 @@
#include <stdint.h>
#include "main.h"
#include "uart.h"
#include "modbus_logic.h"
volatile uint8_t recv_buffer[BUFFERS_SIZE];
volatile uint8_t send_buffer[BUFFERS_SIZE];
extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
uint8_t recv_buffer[BUFFERS_SIZE];
uint8_t send_buffer[BUFFERS_SIZE];
uint16_t bytes_to_send = 0;
uint16_t last_rx_time = 0xFFFF;
@@ -19,55 +21,56 @@ enum send_state cmd_sending = SEND_IDLE;
uint16_t tranfer_errors_count;
extern uint16_t led_time_act;
static void process_incoming_packet();
void process_incoming_packet();
void UART_RxCpltCallback(void)
#define TXEN_ON HAL_GPIO_WritePin(TXEN_GPIO_Port, TXEN_Pin, GPIO_PIN_SET)
#define TXEN_OFF HAL_GPIO_WritePin(TXEN_GPIO_Port, TXEN_Pin, GPIO_PIN_RESET)
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
uint16_t pdu_size;
uint16_t remaining_size;
if (cmd_receiving == RECV_READ_HEADER)
{
// Check destination address
if (recv_buffer[5] != BOARD_ADRESS)
{
cmd_receiving = RECV_ERROR;
return;
}
// Check function code
if (recv_buffer[6] == 3 || recv_buffer[6] == 4 || recv_buffer[6] == 6)
{
cmd_receiving = RECV_READ_COMPLETE;
return;
}
else if (recv_buffer[6] == 0x10)
{
cmd_receiving = RECV_READ_DATA;
pdu_size = *((uint16_t*)(recv_buffer + 2));
// Receive remaining PDU and checksum
remaining_size = pdu_size - (MODBUS_HEADER_SIZE - 4) + 2;
if (remaining_size + MODBUS_HEADER_SIZE <= BUFFERS_SIZE)
UART_Receive_IT(recv_buffer + MODBUS_HEADER_SIZE, remaining_size, 5000);
if (huart->Instance == USART1)
{
if (recv_buffer[5] != BOARD_ADRESS)
{
cmd_receiving = RECV_ERROR;
return;
}
// Check function code
if (recv_buffer[6] == 3 || recv_buffer[6] == 4 || recv_buffer[6] == 6)
{
if(Size==MODBUS_HEADER_SIZE)cmd_receiving = RECV_READ_COMPLETE;
return;
}
else if (recv_buffer[6] == 0x10)
{
uint16_t pdu_size = *((uint16_t*)(recv_buffer + 2));
uint16_t remaining_size = pdu_size - (MODBUS_HEADER_SIZE - 4) + 2;
if (remaining_size + MODBUS_HEADER_SIZE == Size)
cmd_receiving = RECV_READ_COMPLETE;
else
{
cmd_receiving = RECV_ERROR;
tranfer_errors_count++;
}
return;
}
else
{
tranfer_errors_count++;
return;
}
else
{
tranfer_errors_count++;
cmd_receiving = RECV_ERROR;
return;
}
}
else if (cmd_receiving == RECV_READ_DATA)
{
cmd_receiving = RECV_READ_COMPLETE;
}
cmd_receiving = RECV_ERROR;
return;
}
}
}
void UART_TxCpltCallback()
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
cmd_sending = SEND_IDLE;
if (huart->Instance == USART1)
{
cmd_sending = SEND_IDLE;
TXEN_OFF;
}
}
void modbus_loop_iterate()
@@ -76,19 +79,22 @@ void modbus_loop_iterate()
{
if (cmd_receiving == RECV_ERROR)
{
//delay_ms(30); // poor man's way to synchronize packets
if(last_rx_time>=BUS_IDLE_TIME)
{
// poor man's way to synchronize packets
//if(last_rx_time>=BUS_IDLE_TIME)
//{
cmd_receiving = RECV_IDLE;
//TXEN_485 = 1;
//delay_us(10);
//TXEN_485 = 0;
}
//}
}
if (cmd_receiving == RECV_IDLE)
{
cmd_receiving = RECV_READ_HEADER;
UART_Receive_IT(recv_buffer, MODBUS_HEADER_SIZE, 5000);
if(HAL_UARTEx_ReceiveToIdle_DMA(&huart1, recv_buffer, BUFFERS_SIZE)==HAL_OK)
{
cmd_receiving = RECV_READ_HEADER;
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
}
}
else if (cmd_receiving == RECV_READ_COMPLETE)
{
@@ -98,7 +104,8 @@ void modbus_loop_iterate()
}
else if (cmd_sending == SEND_BUSY && bytes_to_send != 0)
{
UART_Transmit_IT(send_buffer, bytes_to_send, 1000);
TXEN_ON;
HAL_UART_Transmit_DMA(&huart1, send_buffer, bytes_to_send);
bytes_to_send = 0;
}
}

View File

@@ -23,6 +23,9 @@
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
@@ -94,9 +97,9 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
/* Peripheral clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* TIM1 interrupt Init */
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0);
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 0);
HAL_NVIC_SetPriority(TIM1_CC_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
/* USER CODE BEGIN TIM1_MspInit 1 */
@@ -230,8 +233,41 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 DMA Init */
/* USART1_RX Init */
hdma_usart1_rx.Instance = DMA1_Channel3;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);
/* USART1_TX Init */
hdma_usart1_tx.Instance = DMA1_Channel2;
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_tx.Init.Mode = DMA_NORMAL;
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
@@ -262,6 +298,10 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* USART1 DMA DeInit */
HAL_DMA_DeInit(huart->hdmarx);
HAL_DMA_DeInit(huart->hdmatx);
/* USART1 interrupt DeInit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */

View File

@@ -56,6 +56,8 @@
/* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV */
@@ -141,6 +143,21 @@ void SysTick_Handler(void)
/* please refer to the startup file (startup_stm32f0xx.s). */
/******************************************************************************/
/**
* @brief This function handles DMA1 channel 2 and 3 interrupts.
*/
void DMA1_Channel2_3_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 0 */
/* USER CODE END DMA1_Channel2_3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx);
HAL_DMA_IRQHandler(&hdma_usart1_rx);
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 1 */
/* USER CODE END DMA1_Channel2_3_IRQn 1 */
}
/**
* @brief This function handles TIM1 break, update, trigger and commutation interrupts.
*/
@@ -175,8 +192,6 @@ void TIM1_CC_IRQHandler(void)
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
USER_UART1_IRQHandler(&huart1);
return;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);

View File

@@ -1,102 +0,0 @@
#include "uart.h"
#include "main.h"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
uint8_t * uart_tx_buf;
uint8_t uart_tx_busy=0;
uint16_t uart_tx_counter=0;
uint16_t uart_tx_len=0;
uint8_t * uart_rx_buf;
uint8_t uart_rx_busy=0;
uint16_t uart_rx_counter=0;
uint16_t uart_rx_len=0;
extern uint16_t last_rx_time;
extern UART_HandleTypeDef huart1;
#define TXEN_ON HAL_GPIO_WritePin(TXEN_GPIO_Port, TXEN_Pin, GPIO_PIN_SET)
#define TXEN_OFF HAL_GPIO_WritePin(TXEN_GPIO_Port, TXEN_Pin, GPIO_PIN_RESET)
void USER_UART1_IRQHandler(UART_HandleTypeDef *huart)
{
uint8_t data;
if((huart1.Instance->ISR & USART_ISR_RXNE) != RESET)
{
last_rx_time = 0;
data = (uint8_t)(huart1.Instance->RDR & (uint8_t)0x00FF); // читает байт из регистра
if(uart_rx_busy)
{
uart_rx_buf[uart_rx_counter]=data;
if(++uart_rx_counter == uart_rx_len)
{
uart_rx_busy = 0;
UART_RxCpltCallback();
}
}
}
if((uart_tx_busy)&&((huart1.Instance->ISR & USART_ISR_TC) != RESET))
{
if(++uart_tx_counter == uart_tx_len)
{
TXEN_OFF;
uart_tx_busy = 0;
UART_TxCpltCallback();
__HAL_UART_DISABLE_IT(&huart1, UART_IT_TC);
}
else
//putchar(uart_tx_buf[uart_tx_counter]);
huart->Instance->TDR=uart_tx_buf[uart_tx_counter];
}
huart->Instance->ICR=0xFFFFFFFF;
}
uint8_t UART_Receive_IT(uint8_t * data, uint16_t len, uint16_t timeout)
{
uint16_t i;
//if(len>UART_RX_LEN)return RET_OVERFLOW;
for(i=0;i<timeout;i++)
{
if(uart_rx_busy!=0)
HAL_Delay(1);
else
break;
}
if(i==timeout) return RET_TIMEOUT;
uart_rx_counter = 0;
uart_rx_len = len;
uart_rx_buf = data;
uart_rx_busy = 1;
return RET_OK;
}
uint8_t UART_Transmit_IT(uint8_t * data, uint16_t len, uint16_t timeout)
{
uint16_t i;
for(i=0;i<timeout;i++)
{
if(uart_tx_busy!=0)
HAL_Delay(1);
else
break;
}
if(i==timeout) return RET_TIMEOUT;
uart_tx_busy = 1;
TXEN_ON;
HAL_Delay(1);
uart_tx_buf = data;
uart_tx_counter = 0;
uart_tx_len = len;
huart1.Instance->TDR=uart_tx_buf[0];
//putchar(uart_tx_buf[0]);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TC);
return RET_OK;
}