设备
- 硬件: 英飞凌XMC4200Platform2Go开发板
- 软件: DAVE
意图
在工业领域中,可能会出现需要修改通信波特率的情况。下面是一些常见的案例:
-
设备更换或升级: 当工业控制系统中的某些设备需要更换或升级时,新设备可能具有不同的通信参数,包括波特率。因此,需要根据新设备的要求修改通信波特率,以确保设备之间的通信正常进行。
-
通信距离变化: 如果在工业控制系统中,某些设备之间的通信距离发生变化,可能需要调整通信波特率。通常情况下,较长的通信距离需要较低的波特率,以确保信号稳定传输。
-
通信质量优化: 有时候,由于外部干扰或通信线路质量等因素影响,工业控制系统中的通信可能会出现问题。此时,通过调整通信波特率来优化通信质量,提高通信稳定性和可靠性是一种常见的解决方案。
-
多设备协同工作: 在一些工业应用中,可能会有多个设备协同工作,它们之间需要进行数据交换和通信。为了最大程度地提高通信效率,可能需要根据不同设备的性能和需求调整通信波特率。
-
网络拓扑结构变化: 工业控制系统中的网络拓扑结构可能会随着系统需求的变化而调整。例如,新增或移除了一些设备,或者改变了设备之间的连接方式。在这种情况下,可能需要重新评估通信参数,包括波特率。
-
特定应用需求: 有些特定的工业应用可能对通信性能有特殊要求。例如,实时性要求较高的应用可能需要较高的通信速率,而对于一些节能环保型应用,可能会采用较低的通信速率以降低功耗。
在以上情况下,需要仔细评估系统需求和通信环境,并根据实际情况调整通信波特率。在进行波特率调整时,应确保所有相关设备的通信参数保持一致,以确保通信的稳定性和可靠性。
方法一:baud rate detection
/*
* Copyright (C) 2014 Infineon Technologies AG. All rights reserved.
*
* Infineon Technologies AG (Infineon) is supplying this software for use with
* Infineon's microcontrollers.
* This file can be freely distributed within development tools that are
* supporting such microcontrollers.
*
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
* OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
*/
#include <XMC4200.h>
#include <DAVE.h> //Declarations from DAVE Code Generation (includes SFR declaration)
#include "xmc_gpio.h"
#include "xmc_uart.h"
#include "xmc_scu.h"
/**
* @brief main() - Application entry point
*
* <b>Details of function</b><br>
* This routine is the application entry point. It is invoked by the device startup code. It is responsible for
* invoking the App initialization dispatcher routine - DAVE_Init() and hosting the place-holder for user application
* code.
*/
Macro and variable for 1. the basic UART LLD test SW: "Hallo!"
/* UART Tx and Rx Pin */
#define UART_RX_PIN P1_4
#define UART_TX_PIN P1_5
#define UART_SYNC_DATA 0x80
#define TIMEOUT_CNT (SystemCoreClock)
XMC_GPIO_CONFIG_t rx_pin_config;
XMC_GPIO_CONFIG_t tx_pin_config;
/* UART configuration */
XMC_USIC_CH_t *uart = XMC_UART0_CH0;
XMC_UART_CH_CONFIG_t uart_config =
{
.baudrate = 115200U,
.oversampling = 16U,
.data_bits = 8U,
.frame_length = 8U,
.stop_bits = 1U,
.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE
};
uint8_t BaudrateDetect(XMC_USIC_CH_t *const channel, uint8_t sync_data, uint8_t oversampling);
uint8_t do_calibration;
macro and ISR for 2. the advanced UART LLD test SW: receive date from keyboard using interrupt (USIC0_SR5)
#define USIC0_SR4 4
#define USIC0_SR5 5
void USIC0_5_IRQHandler(void) // USIC0_5_IRQHandler
{
uint16_t received_data;
uint16_t status;
uint8_t error = 0;
status = XMC_UART_CH_GetStatusFlag(uart);
received_data = XMC_UART_CH_GetReceivedData(uart); // receive data
if(status & XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0) // Format error ?
{
error = 1;
XMC_UART_CH_ClearStatusFlag(uart, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
return;
}
if(status & XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION) // Data lost error ?
{
error = 1;
XMC_UART_CH_ClearStatusFlag(uart, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);
return;
}
if((error == 1) || received_data != UART_SYNC_DATA)
{
XMC_USIC_CH_DisableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);
XMC_USIC_CH_DisableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);
XMC_UART_CH_DisableEvent(uart, 0x00000040); // Set frame error interrupt enable
NVIC_DisableIRQ(USIC0_5_IRQn); // CMSIS function for NVIC control: enable IRQn
do_calibration = 1;
XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_LOW);
}
else
{
// XMC_UART_CH_Transmit(uart, '\n');
XMC_UART_CH_Transmit(uart, received_data); // and send it back
}
}
void delay(uint32_t cnt)
{
while(cnt--);
}
int main(void)
{
uint8_t ret;
uint8_t uart_ready = 0;
XMC_GPIO_SetHardwareControl(P2_1, XMC_GPIO_HWCTRL_DISABLED);
XMC_GPIO_SetMode(P2_1, XMC_GPIO_MODE_OUTPUT_PUSH_PULL);
XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_HIGH);
/*UART initialization sequence*/
XMC_UART_CH_Init(uart, &uart_config);
XMC_UART_CH_SetInputSource(uart, XMC_UART_CH_INPUT_RXD , USIC0_C0_DX0_P1_4);
// XMC_USIC_CH_EnableInputDigitalFilter(uart, XMC_USIC_CH_INPUT_DX0); // Enbale digital filter
XMC_UART_CH_Start(uart); // uart.CCR.mode=UART-> USIC0_CH0 is switched for UART operation mode
/*UART Rx pin configuration*/
rx_pin_config.mode = XMC_GPIO_MODE_INPUT_PULL_UP; // Rx input with internal pull-up
XMC_GPIO_Init(UART_RX_PIN, &rx_pin_config);
/*UART Tx pin configuration*/
tx_pin_config.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH;
tx_pin_config.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2; // Tx output in ALT2
XMC_GPIO_Init(UART_TX_PIN, &tx_pin_config);
XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE); // enable interrupt RI
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, USIC0_SR5); // set USIC0 SR5 for RI
XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE); // 'USIC_AI.007' -> AIR ON
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, USIC0_SR5);
XMC_UART_CH_EnableEvent(uart, 0x00000040); // Set frame error interrupt enable
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_PROTOCOL, USIC0_SR5);
NVIC_SetPriority(USIC0_5_IRQn,2); // CMSIS function for NVIC control: NVIC_SetPriority(IRQn_t IRQn, uint32_t priority): priority=0..63
NVIC_EnableIRQ(USIC0_5_IRQn); // CMSIS function for NVIC control: enable IRQn
while(1U)
{
if(do_calibration == 1)
{
delay(SystemCoreClock/100);
do_calibration = 0;
ret = BaudrateDetect(uart, UART_SYNC_DATA,uart_config.oversampling);
if(ret != 0)
{
while(1);
}
else
{
uart_ready = 1;
}
}
if(uart_ready == 1)
{
XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_HIGH);
XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE); // enable interrupt RI
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, USIC0_SR5); // set USIC0 SR5 for RI
XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE); // 'USIC_AI.007' -> AIR ON
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, USIC0_SR5);
XMC_UART_CH_EnableEvent(uart, 0x00000040); // Set frame error interrupt enable
XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_PROTOCOL, USIC0_SR5);
NVIC_SetPriority(USIC0_5_IRQn,2); // CMSIS function for NVIC control: NVIC_SetPriority(IRQn_t IRQn, uint32_t priority): priority=0..63
NVIC_EnableIRQ(USIC0_5_IRQn); // CMSIS function for NVIC control: enable IRQn
uart_ready = 2;
}
}
return 1;
}
uint8_t CalDetectDataLength(uint8_t u8Data)
{
uint8_t i;
for(i=0; i<8; i++)
{
if((u8Data & (1ul<<i)) == 0)
{
//i++;
}
else
{
break;
}
}
return (i+1); // Return measure length
}
uint8_t CalEdgeTimes(uint8_t u8Data, uint8_t *fall, uint8_t *rise)
{
uint8_t i;
uint8_t fall_cnt = 0, rise_cnt = 0;
uint8_t pre_level = 1;
uint16_t data = 0;
data = (u8Data << 1) | (1ul << 9);
for(i=0; i<10; i++)
{
if( ((data & (1ul<<i)) == 0) && (pre_level == 1))
{
fall_cnt++;
pre_level = 0;
}
if(((data & (1ul<<i)) == (1ul<<i)) && (pre_level == 0))
{
rise_cnt++;
pre_level = 1;
}
}
*fall = fall_cnt;
*rise = rise_cnt;
return 0;
}
uint32_t TrimBaudrate(uint32_t Baudrate)
{
uint32_t rate[9] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400};
uint8_t i;
for ( i = 0; i<8; i++)
{
if(rate[i] > Baudrate)
{
break;
}
}
if(rate[i] - Baudrate < Baudrate - rate[i-1])
return rate[i];
return rate[i-1];
}
uint8_t BaudrateDetect(XMC_USIC_CH_t *const channel, uint8_t sync_data, uint8_t oversampling)
{
uint8_t detect_times = 0;
uint8_t detect_bit_length;
uint32_t detect_data;
float f_detect_baudrate;
uint32_t detect_baudrate;
uint32_t step;
uint32_t Pin;
uint32_t overflow_times = 0;
uint32_t timeout = TIMEOUT_CNT;
uint8_t falling_times, rising_times, total_edge_times;
uint8_t calibration_finish = 0;
static uint8_t dummy;
uint8_t baudrate_correct_result = 0;
detect_bit_length = CalDetectDataLength(sync_data);
CalEdgeTimes(sync_data, &falling_times, &rising_times);
total_edge_times = falling_times + rising_times;
step = 1024 - SystemCoreClock/1000000;
channel->FDR = (step | (1ul << 14)); // STEP = 944, fin = 80MHz / (1024 - 944) = 1MHz @ SystemCoreClock=80000000
Pin = 1000000;
detect_times = 0;
overflow_times = 0;
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
XMC_USIC_CH_SetInputTriggerCombinationMode(channel, XMC_USIC_CH_INPUT_DX0, XMC_USIC_CH_INPUT_COMBINATION_MODE_BOTH_EDGES);
XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement
while(1)
{
timeout--;
if(XMC_UART_CH_GetStatusFlag(channel) & XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION)
{
if(detect_times == 0)
{
detect_times++;
total_edge_times--;
}
else if(detect_times == 1)
{
detect_data = channel->CMTR;
detect_times = 2;
total_edge_times--;
}
else
{
total_edge_times--;
}
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
}
if(XMC_UART_CH_GetStatusFlag(channel) & XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION)
{
if(detect_times == 1)
{
XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
overflow_times++;
}
}
if(total_edge_times == 0)
{
XMC_USIC_CH_SetInputTriggerCombinationMode(channel, XMC_USIC_CH_INPUT_DX0, XMC_USIC_CH_INPUT_COMBINATION_MODE_TRIGGER_DISABLED);
XMC_USIC_CH_DisableTimeMeasurement(channel); // enable time measurement
// Calculate baudrate
detect_data = overflow_times*1024 + detect_data;
f_detect_baudrate = (float)(Pin*detect_bit_length)/(float)detect_data;
detect_baudrate = (uint32_t)f_detect_baudrate;
// detect_baudrate = TrimBaudrate(detect_baudrate);
XMC_USIC_CH_SetBaudrate(channel, detect_baudrate, oversampling);
// XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement
dummy =XMC_UART_CH_GetReceivedData(channel);
dummy =XMC_UART_CH_GetReceivedData(channel);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);
calibration_finish = 1;
//break;
}
if(timeout == 0)
{
XMC_USIC_CH_DisableTimeMeasurement(channel); // enable time measurement
dummy =XMC_UART_CH_GetReceivedData(channel);
dummy =XMC_UART_CH_GetReceivedData(channel);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);
baudrate_correct_result = 1;
break;
}
if(calibration_finish == 1)
{
break;
}
}
return baudrate_correct_result;
}
方法二:master send change request
void ChangeBaudRate(uint32_t ReqBaudRate)
{
uint32_t CurrBaudRate;
/* UART_0 is defined in generatd code uart_conf.c */
extern UART_t UART_0;
/* Function definition can be found in library code */
CurrBaudRate = XMC_USIC_CH_GetBaudrate(UART_0.channel);
/* the method in line below cannot work, because UART_0 is defined constant initially */
/* CurrBaudRate = UART_0.config->channel_config->baudrate; */
if(ReqBaudRate != CurrBaudRate)
{
/* Function definition can be found in generatd code uart_conf.c */
XMC_UART_CH_SetBaudrate(UART_0.channel, ReqBaudRate);
}
}
在使用APP UART后生成的代码中,UART_0如下定义:
/*USIC channel configuration*/
const XMC_UART_CH_CONFIG_t UART_0_channel_config =
{
.baudrate = 19200U,
.data_bits = 8U,
.frame_length = 8U,
.stop_bits = 1U,
.oversampling = 16U,
.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE
};
/*Transmit pin configuration*/
const XMC_GPIO_CONFIG_t UART_0_tx_pin_config =
{
.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2,
.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};
/*Transmit pin configuration used for initializing*/
const UART_TX_CONFIG_t UART_0_tx_pin =
{
.port = (XMC_GPIO_PORT_t *)PORT2_BASE,
.config = &UART_0_tx_pin_config,
.pin = 14U
};
/*UART APP configuration structure*/
const UART_CONFIG_t UART_0_config =
{
.channel_config = &UART_0_channel_config,
.fptr_uart_config = UART_0_init,
.rx_cbhandler = Callback_EndofRX,
.sync_error_cbhandler = NULL,
.rx_noise_error_cbhandler = NULL,
.format_error_bit0_cbhandler = NULL,
.format_error_bit1_cbhandler = NULL,
.collision_error_cbhandler = NULL,
.tx_pin_config = &UART_0_tx_pin,
.mode = UART_MODE_FULLDUPLEX,
.transmit_mode = UART_TRANSFER_MODE_DIRECT,
.receive_mode = UART_TRANSFER_MODE_INTERRUPT,
.tx_fifo_size = XMC_USIC_CH_FIFO_SIZE_32WORDS,
.rx_fifo_size = XMC_USIC_CH_FIFO_SIZE_32WORDS,
};
/*Runtime handler*/
UART_RUNTIME_t UART_0_runtime =
{
.tx_busy = false,
.rx_busy = false,
};
/*APP handle structure*/
UART_t UART_0 =
{
.channel = XMC_UART1_CH0,
.config = &UART_0_config,
.runtime = &UART_0_runtime
};
/*Receive pin configuration*/
const XMC_GPIO_CONFIG_t UART_0_rx_pin_config = {
.mode = XMC_GPIO_MODE_INPUT_TRISTATE,
.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};
在xmc_usic.c中,XMC_USIC_CH_GetBaudrate函数定义为:
uint32_t XMC_USIC_CH_GetBaudrate(XMC_USIC_CH_t *const channel)
{
uint32_t divider;
if ((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) == USIC_CH_BRG_CTQSEL_Msk)
{
// CTQSEL = 3
divider = 2;
}
else
{
// CTQSEL = 0, 1, or 2
divider = (channel->BRG & USIC_CH_BRG_PPPEN_Msk) ? 2 : 1;
if ((((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) >> USIC_CH_BRG_CTQSEL_Pos) & 0x1) == 0)
{
// CTQSEL = 0 or 2
divider *= ((channel->BRG & USIC_CH_BRG_PDIV_Msk) >> USIC_CH_BRG_PDIV_Pos) + 1;
if ((((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) >> USIC_CH_BRG_CTQSEL_Pos) & 0x2) != 0)
{
// CTQSEL = 2
divider *= 2;
}
}
}
divider *= ((channel->BRG & USIC_CH_BRG_PCTQ_Msk) >> USIC_CH_BRG_PCTQ_Pos) + 1;
divider *= ((channel->BRG & USIC_CH_BRG_DCTQ_Msk) >> USIC_CH_BRG_DCTQ_Pos) + 1;
uint32_t fperi = XMC_SCU_CLOCK_GetPeripheralClockFrequency();
float baudrate;
if ((channel->FDR & USIC_CH_FDR_DM_Msk) == XMC_USIC_CH_BRG_CLOCK_DIVIDER_MODE_FRACTIONAL)
{
baudrate = fperi * (((channel->FDR & USIC_CH_FDR_STEP_Msk) >> USIC_CH_FDR_STEP_Pos) / 1024.0F);
}
else
{
/* Normal divider mode */
baudrate = fperi * (1.0F / (1024 - ((channel->FDR & USIC_CH_FDR_STEP_Msk) >> USIC_CH_FDR_STEP_Pos)));
}
baudrate /= divider;
return (uint32_t)baudrate;
}
在xmc_uart.c中,函数XMC_UART_CH_SetBaudrate被定义
XMC_UART_CH_STATUS_t XMC_UART_CH_SetBaudrate(XMC_USIC_CH_t *const channel, uint32_t rate, uint32_t oversampling)
{
XMC_UART_CH_STATUS_t status;
status = XMC_UART_CH_STATUS_ERROR;
if ((rate <= (XMC_SCU_CLOCK_GetPeripheralClockFrequency() >> 2U)) && (oversampling >= XMC_UART_CH_OVERSAMPLING_MIN_VAL))
{
if (XMC_USIC_CH_SetBaudrate(channel, rate, oversampling) == XMC_USIC_CH_STATUS_OK)
{
status = XMC_UART_CH_STATUS_OK;
}
}
return status;
}