rx_bad = 0;
usart_set_mode(MODBUS_USART, USART_MODE_RX);
usart_enable_rx_interrupt(MODBUS_USART);
rx_bad = 0;
usart_set_mode(MODBUS_USART, USART_MODE_RX);
usart_enable_rx_interrupt(MODBUS_USART);
timer_set_prescaler(MODBUS_TIMER, CPU_CLOCK_MHZ-1); // 1 tick = 1 μs
timer_set_mode(MODBUS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_DOWN);
timer_update_on_overflow(MODBUS_TIMER);
timer_set_prescaler(MODBUS_TIMER, CPU_CLOCK_MHZ-1); // 1 tick = 1 μs
timer_set_mode(MODBUS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_DOWN);
timer_update_on_overflow(MODBUS_TIMER);
tx_init();
} else if (rx_buf[0] == 0x00) {
// Broadcast frame: process, but do not reply
tx_init();
} else if (rx_buf[0] == 0x00) {
// Broadcast frame: process, but do not reply
ERR_ILLEGAL_FUNCTION = 0x01,
ERR_ILLEGAL_DATA_ADDRESS = 0x02,
ERR_ILLEGAL_DATA_VALUE = 0x03,
ERR_ILLEGAL_FUNCTION = 0x01,
ERR_ILLEGAL_DATA_ADDRESS = 0x02,
ERR_ILLEGAL_DATA_VALUE = 0x03,
return report_error(ERR_ILLEGAL_DATA_VALUE);
modbus_set_coil(addr, value);
return report_error(ERR_ILLEGAL_DATA_VALUE);
modbus_set_coil(addr, value);
return report_error(ERR_ILLEGAL_DATA_ADDRESS);
modbus_set_holding_register(addr, value);
return report_error(ERR_ILLEGAL_DATA_ADDRESS);
modbus_set_holding_register(addr, value);
for (u16 i = 0; i < count; i++)
modbus_set_coil(start + i, rx_frame[i/8] & (1U << (i%8)));
for (u16 i = 0; i < count; i++)
modbus_set_coil(start + i, rx_frame[i/8] & (1U << (i%8)));
for (u16 i = 0; i < count; i++)
modbus_set_holding_register(start + i, read_u16());
for (u16 i = 0; i < count; i++)
modbus_set_holding_register(start + i, read_u16());
u16 reg = modbus_get_holding_register(addr);
reg = (reg & and_mask) | (or_mask & ~and_mask);
modbus_set_holding_register(addr, reg);
u16 reg = modbus_get_holding_register(addr);
reg = (reg & and_mask) | (or_mask & ~and_mask);
modbus_set_holding_register(addr, reg);