4821 views|2 replies

54

Posts

0

Resources
The OP
 

[Xianji HPM6750 Review] Bare Metal Transplantation agile_modbus [Copy link]

 This post was last edited by xiashuang on 2022-7-19 10:51

Modbus is a commonly used industrial communication protocol. This time, I ported Modbus RTU on HPM, mainly to get familiar with UART and timer. I originally wanted to port freemodbus, but freemodbus only supports single slave. Some time ago, I saw agile_modbus in the RT-THREAD community. After reading the examples, I found that it is as simple as libmodbus and supports multiple hosts and multiple slaves. I just wanted to try the UART and timer of HPM6750, so I used UART receiving and sending interrupts and timer timeout interrupts to implement modbus rtu.

The migration steps are as follows: 1. Download the agile_modbus file from GitHub and add the relevant source files to the project

2. Add header file path

3. Protocol stack initialization

/*init modbus stack*/
uint8_t ctx_send_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
uint8_t ctx_read_buf[AGILE_MODBUS_MAX_ADU_LENGTH];

agile_modbus_rtu_t ctx_rtu;
agile_modbus_t *ctx = &ctx_rtu._ctx;
agile_modbus_rtu_init(&ctx_rtu, ctx_send_buf, sizeof(ctx_send_buf), ctx_read_buf, sizeof(ctx_read_buf));
agile_modbus_set_slave(ctx, 1);

4. The serial port uses uart13, and the interrupt code is as follows

void uart_isr(void)
{
uint8_t c;
uint8_t uart_irq_state = uart_get_irq_id(TEST_UART1);
if (uart_irq_state & uart_intr_id_rx_data_avail)
{
if (status_success != uart_receive_byte(TEST_UART1, &c)) {
while (1) {
}
}
//Timer reset count
gptmr_channel_reset_count(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
//printf("R");
//Start timerif
(buff_index == 0)
{
gptmr_start_counter(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
uart_rx_outtime = 0;//Receive timeout status is 0
//printf("S");
}

data_buff[buff_index] = c;
buff_index++;
//Too much received data, receive againif
(buff_index >= 260) {
//uart_disable_irq(TEST_UART1, uart_intr_rx_data_avail_or_timeout);
//uart_enable_irq(TEST_UART1, uart_intr_tx_slot_avail);
buff_index = 0;
}

}

if (uart_irq_state & uart_intr_id_tx_slot_avail)
{
if (status_success != uart_send_byte(TEST_UART1, data_buff[data_count])) {
while (1) {
}
}
data_count ++;
if(data_count >= buff_index){
buff_index = 0;
data_count = 0;
uart_rx_outtime = 0;
uart_flush(TEST_UART1);
uart_disable_irq(TEST_UART1, uart_intr_tx_slot_avail);
uart_enable_irq(TEST_UART1, uart_intr_rx_data_avail_or_timeout);
}
}
}

SDK_DECLARE_EXT_ISR_M(TEST_UART_IRQ1, uart_isr)

5. Timer configuration

void modbus_timer_create(uint32_t ms, modbus_timer_cb cb)
{
uint32_t gptmr_freq;
gptmr_channel_config_t config;
gptmr_channel_get_default_config(MODBUS_CALLBACK_TIMER, &config);
clock_add_to_group(MODBUS_CALLBACK_TIMER_CLK_NAME, 0); freq
= clock_get_frequency(MODBUS_CALLBACK_TIMER_CLK_NAME);
config.reload = gptmr_freq / 1000 * ms;
gptmr_channel_config(MODBUS_CALLBACK_TIMER , MODBUS_CALLBACK_TIMER_CH, &config, false);
gptmr_enable_irq(MODBUS_CALLBACK_TIMER, GPTMR_CH_RLD_IRQ_MASK(MODBUS_CALLBACK_TIMER_CH));
intc_m_enable_irq_with_priority(MODBUS_CALLBACK_TIMER_IRQ, 1);

//gptmr_start_counter(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
}

6. The timer is started when the first receive interrupt of UART is received. Each subsequent interrupt timer is reset. After exceeding T3.5, the timer timeout flag is updated and the modbus protocol stack is processed. If data needs to be sent, send the data

if(uart_rx_outtime == 1)
{
//printf("t");
uart_rx_outtime = 0;
memcpy(ctx_read_buf,data_buff,buff_index);
int send_len = agile_modbus_slave_handle(ctx, buff_index, 0, slave_callback, NULL);
if (send_len > 0)
{
data_count = 0;
buff_index = send_len;
memcpy(data_buff,ctx_send_buf,buff_index);
uart_flush(TEST_UART1);
uart_enable_irq(TEST_UART1, uart_intr_tx_slot_avail);
uart_disable_irq(TEST_UART1, uart_intr_rx_data_avail_or_time out);
}
else{
buff_index = 0;
}
}

7.slave_callback does not need to be modified, because I use logic, so comment out the exclusive access

Summary: The interrupt status reading in the UART interrupt receiving and sending code provided by HPM is not reasonable in actual use. If blocking is not used, the program will be stuck in the while (1) in the receiving interrupt processing. Adding an intermediate variable uint8_t uart_irq_state = uart_get_irq_id(TEST_UART1) and using the intermediate variable to judge the status is OK. It is suspected that each reading of the interrupt status will clear the interrupt register interrupt. agile_modbus has more porting and usage orders than freemodbus. If you need to use modbus, try it.

This post is from Domestic Chip Exchange

Latest reply

Thank you for the very detailed evaluation sharing! Regarding the final summary, uart_isr is an example in the example. If the application has different requirements, it can be written according to the specific requirements. Thank you! !  Details Published on 2022-7-21 14:31
 
 

7462

Posts

2

Resources
2
 

I looked at this agile_modbus, thanks for sharing, I will try it when I have a chance

This post is from Domestic Chip Exchange
Personal signature

默认摸鱼,再摸鱼。2022、9、28

 
 
 

1

Posts

2

Resources
3
 
Thank you for the very detailed evaluation sharing! Regarding the final summary, uart_isr is an example in the example. If the application has different requirements, it can be written according to the specific requirements. Thank you! !
This post is from Domestic Chip Exchange
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list