HAL_TIM_Base_MspInit()
and HAL_UART_MspInit()
functions, this will make your life easier if you connect other timers and usart'y.assert()
on assert_param()
, and add stm32f3xx_hal.h , if you use a processor of another series, then instead of this, use the appropriate library.ENTER_CRITICAL_SECTION( )
and EXIT_CRITICAL_SECTION( )
macros. We replace them with __disable_irq()
and __enable_irq()
respectively. void foo() { ENTER_CRITICAL_SECTION(); // // EXIT_CRITICAL_SECTION(); // , , bar() } void bar() { ENTER_CRITICAL_SECTION(); // foo(); // , EXIT_CRITICAL_SECTION(); // =( }
UART_IRQ_Handler()
, which will be used for a bit of a crutch implementation of the interrupt response. /* * FreeModbus Libary: BARE Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: port.h,v 1.1 2006/08/22 21:35:13 wolti Exp $ */ #ifndef _PORT_H #define _PORT_H #include "stm32f3xx_hal.h" #include <inttypes.h> #define INLINE inline #define PR_BEGIN_EXTERN_C extern "C" { #define PR_END_EXTERN_C } // #define ENTER_CRITICAL_SECTION( ) __disable_irq() #define EXIT_CRITICAL_SECTION( ) __enable_irq() // #define assert(val) assert_param(val) typedef uint8_t BOOL; typedef unsigned char UCHAR; typedef char CHAR; typedef uint16_t USHORT; typedef int16_t SHORT; typedef uint32_t ULONG; typedef int32_t LONG; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif // callback uart BOOL UART_IRQ_Handler(USART_TypeDef * usart); #endif
stm32f3xx_hal_tim.h
, from which you need the TIM_COUNTERMODE_UP
constant.xMBPortTimersInit()
function is xMBPortTimersInit()
timer initialization. We expect that it will tick every 50 ÎĽs.static TIM_HandleTypeDef
, globalstatic uint16_t
, globalstatic uint16_t
, global htim.Instance = TIM6; // , 6 htim.Init.CounterMode = TIM_COUNTERMODE_UP; // ( 0 ) /* , 32 HAL_RCC_GetPCLK1Freq() - PCLK1, 32000000 1000000, 1 -1 - : , 0 - 1, 1 - 2 ..*/ htim.Init.Prescaler = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1; // 50 , -1, , htim.Init.Period = 50 - 1; // , timeout = usTim1Timerout50us; // , , HAL return HAL_OK == HAL_TIM_Base_Init(&htim) ? TRUE : FALSE;
vMBPortTimersEnable()
function. There are 2 simple steps: downcounter = timeout; HAL_TIM_Base_Start_IT(&htim);
vMBPortTimersDisable()
function. Then just turn off the timer. HAL_TIM_Base_Stop_IT(&htim);
HAL_TIM_Base_Stop_IT()
timer: // , , if(__HAL_TIM_GET_FLAG(&htim, TIM_FLAG_UPDATE) != RESET && __HAL_TIM_GET_IT_SOURCE(&htim, TIM_IT_UPDATE) !=RESET) { __HAL_TIM_CLEAR_IT(&htim, TIM_IT_UPDATE); // if (!--downcounter) // , prvvTIMERExpiredISR(); // callback }
/* * FreeModbus Libary: BARE Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $ */ /* ----------------------- Platform includes --------------------------------*/ #include "port.h" #include "stm32f3xx_hal_tim.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- static functions ---------------------------------*/ static void prvvTIMERExpiredISR( void ); static TIM_HandleTypeDef htim; static uint16_t timeout = 0; static uint16_t downcounter = 0; /* ----------------------- Start implementation -----------------------------*/ BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) { htim.Instance = TIM6; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Prescaler = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1; htim.Init.Period = 50 - 1; timeout = usTim1Timerout50us; return HAL_OK == HAL_TIM_Base_Init(&htim) ? TRUE : FALSE; } inline void vMBPortTimersEnable( ) { /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */ downcounter = timeout; HAL_TIM_Base_Start_IT(&htim); } inline void vMBPortTimersDisable( ) { /* Disable any pending timers. */ HAL_TIM_Base_Stop_IT(&htim); } /* Create an ISR which is called whenever the timer has expired. This function * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that * the timer has expired. */ static void prvvTIMERExpiredISR( void ) { ( void )pxMBPortCBTimerExpired( ); } void TIM6_DAC1_IRQHandler(void) { /* TIM Update event */ if(__HAL_TIM_GET_FLAG(&htim, TIM_FLAG_UPDATE) != RESET && __HAL_TIM_GET_IT_SOURCE(&htim, TIM_IT_UPDATE) !=RESET) { __HAL_TIM_CLEAR_IT(&htim, TIM_IT_UPDATE); if (!--downcounter) prvvTIMERExpiredISR(); } }
static UART_HandleTypeDef
static GPIO_TypeDef *
static uint16_t
vMBPortSerialEnable()
function. Here we turn to the "hidden opportunities" HAL. if (xRxEnable) { // // (. rs485) HAL_GPIO_WritePin(DE_Port, DE_Pin, GPIO_PIN_RESET); __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE); // , } else { __HAL_UART_DISABLE_IT(&huart, UART_IT_RXNE); // } if (xTxEnable) { // // (. rs485) HAL_GPIO_WritePin(DE_Port, DE_Pin, GPIO_PIN_SET); __HAL_UART_ENABLE_IT(&huart, UART_IT_TXE); // , } else { __HAL_UART_DISABLE_IT(&huart, UART_IT_TXE); // }
xMBPortSerialInit()
. Made it more or less universal, it initializes the specified UART itself, but do not forget that the part with MSP initialization should be generated: initialization of pins, interrupts, etc. huart.Init.Mode = UART_MODE_TX_RX; // huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; // ( rs485) // , , huart.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED; huart.Init.OverSampling = UART_OVERSAMPLING_16; // - huart.Init.StopBits = UART_STOPBITS_1; // - huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; // : UART, switch (ucPORT) { case 0: huart.Instance = USART1; DE_Port = GPIOA; DE_Pin = GPIO_PIN_12; break; case 1: huart.Instance = USART2; DE_Port = GPIOA; DE_Pin = GPIO_PIN_1; break; case 2: huart.Instance = USART3; DE_Port = GPIOB; DE_Pin = GPIO_PIN_14; break; default: // , , , - return FALSE; } // huart.Init.BaudRate = ulBaudRate; // switch (ucDataBits) { case 8: huart.Init.WordLength = UART_WORDLENGTH_8B; break; case 9: huart.Init.WordLength = UART_WORDLENGTH_9B; break; default: // , , , - return FALSE; } // switch (eParity) { case MB_PAR_NONE: huart.Init.Parity = UART_PARITY_NONE; break; case MB_PAR_EVEN: huart.Init.Parity = UART_PARITY_EVEN; break; case MB_PAR_ODD: huart.Init.Parity = UART_PARITY_ODD; break; default: // , , , - return FALSE; } // , rs485 return HAL_OK == HAL_RS485Ex_Init(&huart, UART_DE_POLARITY_HIGH, 0, 0) ? TRUE : FALSE;
xMBPortSerialPutByte()
and xMBPortSerialGetByte()
. Here we will do hardcore low-level (for HAL) IO, using UART's registers.*pucByte = huart.Instance->RDR
huart.Instance->TDR = ucByte
UART_IRQ_Handler()
function, which we described in port.h. It will be responsible for intercepting I / O interrupts. The basic idea: if the interruption is “our”, i.e. from our port, and what we are waiting for, we return TRUE
- this means that we intercepted it. if (usart == huart.Instance) { // , if((__HAL_UART_GET_IT(&huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_RXNE) != RESET)) { // , pxMBFrameCBByteReceived(); // __HAL_UART_SEND_REQ(&huart, UART_RXDATA_FLUSH_REQUEST); // return TRUE; // , } if((__HAL_UART_GET_IT(&huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_TXE) != RESET)) { // , pxMBFrameCBTransmitterEmpty(); // return TRUE; // , } } return FALSE; // , ,
/* * FreeModbus Libary: BARE Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $ */ #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- static functions ---------------------------------*/ static UART_HandleTypeDef huart; static GPIO_TypeDef * DE_Port; static uint16_t DE_Pin; /* ----------------------- Start implementation -----------------------------*/ void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) { /* If xRXEnable enable serial receive interrupts. If xTxENable enable * transmitter empty interrupts. */ if (xRxEnable) { HAL_GPIO_WritePin(DE_Port, DE_Pin, GPIO_PIN_RESET); __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE); } else { __HAL_UART_DISABLE_IT(&huart, UART_IT_RXNE); } if (xTxEnable) { HAL_GPIO_WritePin(DE_Port, DE_Pin, GPIO_PIN_SET); __HAL_UART_ENABLE_IT(&huart, UART_IT_TXE); } else { __HAL_UART_DISABLE_IT(&huart, UART_IT_TXE); } } BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { huart.Init.Mode = UART_MODE_TX_RX; huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED; huart.Init.OverSampling = UART_OVERSAMPLING_16; huart.Init.StopBits = UART_STOPBITS_1; huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; switch (ucPORT) { case 0: huart.Instance = USART1; DE_Port = GPIOA; DE_Pin = GPIO_PIN_4; break; case 1: huart.Instance = USART2; DE_Port = GPIOA; DE_Pin = GPIO_PIN_1; break; case 2: huart.Instance = USART3; DE_Port = GPIOB; DE_Pin = GPIO_PIN_14; break; default: return FALSE; } huart.Init.BaudRate = ulBaudRate; switch (ucDataBits) { case 8: huart.Init.WordLength = UART_WORDLENGTH_8B; break; case 9: huart.Init.WordLength = UART_WORDLENGTH_9B; break; default: return FALSE; } switch (eParity) { case MB_PAR_NONE: huart.Init.Parity = UART_PARITY_NONE; break; case MB_PAR_EVEN: huart.Init.Parity = UART_PARITY_EVEN; break; case MB_PAR_ODD: huart.Init.Parity = UART_PARITY_ODD; break; default: return FALSE; } return HAL_OK == HAL_RS485Ex_Init(&huart, UART_DE_POLARITY_HIGH, 0, 0); } BOOL xMBPortSerialPutByte( CHAR ucByte ) { /* Put a byte in the UARTs transmit buffer. This function is called * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been * called. */ huart.Instance->TDR = ucByte; return TRUE; } BOOL xMBPortSerialGetByte( CHAR * pucByte ) { /* Return the byte in the UARTs receive buffer. This function is called * by the protocol stack after pxMBFrameCBByteReceived( ) has been called. */ *pucByte = huart.Instance->RDR; return TRUE; } BOOL UART_IRQ_Handler(USART_TypeDef * usart) { if (usart == huart.Instance) { if((__HAL_UART_GET_IT(&huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_RXNE) != RESET)) { pxMBFrameCBByteReceived(); __HAL_UART_SEND_REQ(&huart, UART_RXDATA_FLUSH_REQUEST); return TRUE; } if((__HAL_UART_GET_IT(&huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_TXE) != RESET)) { pxMBFrameCBTransmitterEmpty(); return TRUE; } } return FALSE; }
UART_IRQ_Handler()
function. To fix this, you need to visit the stm32f3xx_it.c file. There we add include for port.h. The following lines must be added to all USARTx_IRQ_Handler's (in our case, USART1_IRQ_Handle()
). // , if (FALSE != UART_IRQ_Handler(USART1)) return;
/** ****************************************************************************** * @file stm32f3xx_it.c * @brief Interrupt Service Routines. ****************************************************************************** * * COPYRIGHT(c) 2016 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f3xx_hal.h" #include "stm32f3xx.h" #include "stm32f3xx_it.h" /* USER CODE BEGIN 0 */ #include "port.h" /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ extern UART_HandleTypeDef huart1; /******************************************************************************/ /* Cortex-M4 Processor Interruption and Exception Handlers */ /******************************************************************************/ /** * @brief This function handles System tick timer. */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); HAL_SYSTICK_IRQHandler(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } /******************************************************************************/ /* STM32F3xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ /* For the available peripheral interrupt handler names, */ /* please refer to the startup file (startup_stm32f3xx.s). */ /******************************************************************************/ /** * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ if (FALSE != UART_IRQ_Handler(USART1)) return; /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
eMBRTUSend()
). eMBErrorCode eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) { eMBErrorCode eStatus = MB_ENOERR; USHORT usCRC16; ENTER_CRITICAL_SECTION( ); /* Check if the receiver is still in idle state. If not we where to * slow with processing the received frame and the master sent another * frame on the network. We have to abort sending the frame. */ if( eRcvState == STATE_RX_IDLE ) { /* First byte before the Modbus-PDU is the slave address. */ pucSndBufferCur = ( UCHAR * ) pucFrame - 1; usSndBufferCount = 1; /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */ pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress; usSndBufferCount += usLength; /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */ usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ); ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF ); ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 ); usSndBufferCount++; // /* Activate the transmitter. */ eSndState = STATE_TX_XMIT; vMBPortSerialEnable( FALSE, TRUE ); } else { eStatus = MB_EIO; } EXIT_CRITICAL_SECTION( ); return eStatus; }
/*! \brief If Modbus ASCII support is enabled. */ #define MB_ASCII_ENABLED ( 0 ) /*! \brief If Modbus RTU support is enabled. */ #define MB_RTU_ENABLED ( 1 ) /*! \brief If Modbus TCP support is enabled. */ #define MB_TCP_ENABLED ( 0 )
Source: https://habr.com/ru/post/279747/
All Articles