目录
- 1 前言
- 2 问题集锦及解答
- 2.1 radio芯片在接包时,preamble、header和Rx done三个中断产生顺序是怎么样的?谁先谁后?
- 2.2 产生了Header error中断后,radio芯片会继续接收本包还是立马丢弃本包?
- 2.3 产生了CRC error中断后,radio芯片会继续接收本包还是立马丢弃本包?Rx done和CRC error中断是否应该嵌套处理?
- 2.4 如果不清除中断,radio的中断引脚DIOx是不是一直是高电平?
- 2.5 如何正确配置中断?
1 前言
本章介绍在使用LoRa芯片时,对preamble、header、CRC和RX Done各个中断产生的顺序进行解读,本章以SX126x为例,但结论是同样适合其他系列的芯片的。要理解本章节内容,需要先了解一下LoRa物理层协议结构,不然理解起来太抽象了。在此,我再次将LoRa协议图贴出来,如下。
2 问题集锦及解答
在开始之前,我先将使用的处理中断的代码粘贴出来,理解一下代码中对中断的处理,这样结合后续的实验log来理解radio的中断产生顺序。
void apps_common_sx126x_irq_process( const void* context )
{
if( irq_fired == true )
{
irq_fired = false;
sx126x_irq_mask_t irq_regs;
sx126x_get_and_clear_irq_status( context, &irq_regs );
if( ( irq_regs & SX126X_IRQ_TX_DONE ) == SX126X_IRQ_TX_DONE )
{
HAL_DBG_TRACE_INFO( "Tx done\n" );
on_tx_done( );
}
if( ( irq_regs & SX126X_IRQ_RX_DONE ) == SX126X_IRQ_RX_DONE )
{
HAL_DBG_TRACE_INFO( "Rx done\n" );
ASSERT_SX126X_RC( sx126x_handle_rx_done( context ) );
if( PACKET_TYPE == SX126X_PKT_TYPE_GFSK )
{
sx126x_pkt_status_gfsk_t pkt_status;
sx126x_get_gfsk_pkt_status( context, &pkt_status );
if( pkt_status.rx_status.crc_error == true )
{
HAL_DBG_TRACE_ERROR( "CRC error from packet status\n" );
// The CRC error call to on_crc_error is handled with SX126X_IRQ_CRC_ERROR
}
else if( pkt_status.rx_status.adrs_error == true )
{
HAL_DBG_TRACE_ERROR( "Address error from packet status\n" );
on_rx_error( );
}
else if( pkt_status.rx_status.length_error == true )
{
HAL_DBG_TRACE_ERROR( "Length error from packet status\n" );
on_rx_error( );
}
else
{
on_rx_done( );
}
}
else
{
on_rx_done( );
}
}
if( ( irq_regs & SX126X_IRQ_PREAMBLE_DETECTED ) == SX126X_IRQ_PREAMBLE_DETECTED )
{
HAL_DBG_TRACE_INFO( "Preamble detected\n" );
on_preamble_detected( );
}
if( ( irq_regs & SX126X_IRQ_SYNC_WORD_VALID ) == SX126X_IRQ_SYNC_WORD_VALID )
{
HAL_DBG_TRACE_INFO( "Syncword valid\n" );
on_syncword_valid( );
}
if( ( irq_regs & SX126X_IRQ_HEADER_VALID ) == SX126X_IRQ_HEADER_VALID )
{
HAL_DBG_TRACE_INFO( "Header valid\n" );
on_header_valid( );
}
if( ( irq_regs & SX126X_IRQ_HEADER_ERROR ) == SX126X_IRQ_HEADER_ERROR )
{
HAL_DBG_TRACE_ERROR( "Header error\n" );
on_header_error( );
}
if( ( irq_regs & SX126X_IRQ_CRC_ERROR ) == SX126X_IRQ_CRC_ERROR )
{
HAL_DBG_TRACE_ERROR( "CRC error\n" );
on_crc_error( );
}
if( ( irq_regs & SX126X_IRQ_CAD_DONE ) == SX126X_IRQ_CAD_DONE )
{
HAL_DBG_TRACE_INFO( "CAD done\n" );
if( ( irq_regs & SX126X_IRQ_CAD_DETECTED ) == SX126X_IRQ_CAD_DETECTED )
{
HAL_DBG_TRACE_INFO( "Channel activity detected\n" );
on_cad_done_detected( );
}
else
{
HAL_DBG_TRACE_INFO( "No channel activity detected\n" );
on_cad_done_undetected( );
}
}
if( ( irq_regs & SX126X_IRQ_TIMEOUT ) == SX126X_IRQ_TIMEOUT )
{
HAL_DBG_TRACE_WARNING( "Rx timeout\n" );
on_rx_timeout( );
}
if( ( irq_regs & SX126X_IRQ_LR_FHSS_HOP ) == SX126X_IRQ_LR_FHSS_HOP )
{
HAL_DBG_TRACE_INFO( "FHSS hop done\n" );
on_fhss_hop_done( );
}
}
}
/* 打开全部中断并将其全部映射到DIO1上 */
sx126x_set_dio_irq_params( context, SX126X_IRQ_ALL, SX126X_IRQ_ALL, SX126X_IRQ_NONE, SX126X_IRQ_NONE);
2.1 radio芯片在接包时,preamble、header和Rx done三个中断产生顺序是怎么样的?谁先谁后?
准备两个devices,一个TX,一个RX。
log结果如下:
INFO: irq_regs = 0x04
INFO: Preamble detected
INFO: on_preamble_detected
INFO: irq_regs = 0x10
INFO: Header valid
INFO: on_header_valid
INFO: irq_regs = 0x02
INFO: Rx done
Packet content - (21 bytes):
F5 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14
INFO: Packet status:
INFO: - RSSI packet = -75 dBm
INFO: - Signal RSSI packet = -76 dBm
INFO: - SNR packet = 7 dB
小结:三个中断的产生是有先后顺序的,并且这些中断并不是一下产生的,而是一个一个来的。
2.2 产生了Header error中断后,radio芯片会继续接收本包还是立马丢弃本包?
准备两个devices,一个TX,一个RX。
log结果如下:
INFO: irq_regs = 0x04
INFO: Preamble detected
INFO: on_preamble_detected
INFO: irq_regs = 0x22 //此处0x22代表两个中断,一个 Rx done,一个Header error。
INFO: Rx done
Packet content - (21 bytes):
2C 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14
INFO: Packet status:
INFO: - RSSI packet = -79 dBm
INFO: - Signal RSSI packet = -78 dBm
INFO: - SNR packet = 7 dB
ERROR: Header error
INFO: on_header_error
INFO: irq_regs = 0x04
INFO: Preamble detected
INFO: on_preamble_detected
INFO: irq_regs = 0x10
INFO: Header valid
INFO: on_header_valid
INFO: irq_regs = 0x02
INFO: Rx done
Packet content - (21 bytes):
2D 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14
INFO: Packet status:
INFO: - RSSI packet = -78 dBm
INFO: - Signal RSSI packet = -79 dBm
INFO: - SNR packet = 7 dB
小结:结合上边代码和log分析,产生了Header error中断后,radio也不会停止接收本包,也不会立马产生Header error中断,而是等产生Rx done中断后,两个中断一起产生。(注意本代码在检测到Header error时,没有任何处理,使用者可以自己添加逻辑决定是否要丢弃本包。)
2.3 产生了CRC error中断后,radio芯片会继续接收本包还是立马丢弃本包?Rx done和CRC error中断是否应该嵌套处理?
准备两个devices,一个TX,一个RX。
log结果如下:
INFO: irq_regs = 0x04
INFO: Preamble detected
INFO: on_preamble_detected
INFO: irq_regs = 0x10
INFO: Header valid
INFO: on_header_valid
INFO: irq_regs = 0x42 //此处0x22代表两个中断,一个 Rx done,一个CRC error。
INFO: Rx done
Packet content - (21 bytes):
B5 01 02 03 04 05 06 9E 48 CD A2 7F 09 BF E9 B1
BD 01 3B 81 AF
INFO: Packet status:
INFO: - RSSI packet = -78 dBm
INFO: - Signal RSSI packet = -80 dBm
INFO: - SNR packet = 4 dB
ERROR: CRC error
INFO: on_crc_error
小结:首先,即使产生了CRC error中断,radio也不会停止接收本包,也不会立马产生CRC error中断,而是等产生Rx done中断后,两个中断一起产生。本套代码Rx done和CRC error中断没有嵌套处理,但在做项目应用时,建议做嵌套处理,即本包产生CRC error了,就丢掉。
2.4 如果不清除中断,radio的中断引脚DIOx是不是一直是高电平?
答案是的,我们知道MCU需要使用一个GPIO pin连接radio的DIOx引脚,并配置为输入、上升沿中断,来检测DIOx引脚的中断。如果中断来了,DIOx引脚会从低电平拉高。接下来就需要MCU去读取radio中断标志位了,读完清除,下边的程序是对sx126x_get_and_clear_irq_status()
封装。如果不清除,则DIOx引脚会一直处于高电平。
sx126x_status_t sx126x_get_and_clear_irq_status( const void* context, sx126x_irq_mask_t* irq )
{
sx126x_irq_mask_t sx126x_irq_mask = SX126X_IRQ_NONE;
sx126x_status_t status = sx126x_get_irq_status( context, &sx126x_irq_mask );
if( ( status == SX126X_STATUS_OK ) && ( sx126x_irq_mask != 0 ) )
{
status = sx126x_clear_irq_status( context, sx126x_irq_mask );
}
if( ( status == SX126X_STATUS_OK ) && ( irq != NULL ) )
{
*irq = sx126x_irq_mask;
}
return status;
}
2.5 如何正确配置中断?
下边程序是对中断配置函数的注释。
/**
1. @brief Set which interrupt signals are redirected to the dedicated DIO pin
2. 3. @remark By default, no interrupt signal is redirected.
3. 5. @remark An interrupt will not occur until it is enabled system-wide, even if it is redirected to a specific DIO.
4. 7. @remark The DIO pin will remain asserted until all redirected interrupt signals are cleared with a call to @ref
5. sx126x_clear_irq_status.
6. 10. @remark DIO2 and DIO3 are shared with other features. See @ref sx126x_set_dio2_as_rf_sw_ctrl and @ref
7. sx126x_set_dio3_as_tcxo_ctrl
8. 13. @param [in] context Chip implementation context
9. @param [in] irq_mask Variable that holds the system interrupt mask
10. @param [in] dio1_mask Variable that holds the interrupt mask for dio1
11. @param [in] dio2_mask Variable that holds the interrupt mask for dio2
12. @param [in] dio3_mask Variable that holds the interrupt mask for dio3
13. 19. @returns Operation status
14. 21. @see sx126x_clear_irq_status, sx126x_get_irq_status, sx126x_set_dio2_as_rf_sw_ctrl, sx126x_set_dio3_as_tcxo_ctrl
*/
sx126x_status_t sx126x_set_dio_irq_params( const void* context, const uint16_t irq_mask, const uint16_t dio1_mask,
const uint16_t dio2_mask, const uint16_t dio3_mask );
讲一下使用的重点,第二参数irq_mask
决定了要打开哪些中断,第三个参数dio1_mask
决定了将哪些中断映射到DIO1引脚上。举个例子说明用法,如果配置第二个参数打开Preamble detected、Header valid和Rx done中断,分两种情况:
- 第三个参数只配置了Rx done中断,则结果就是接收完一包后,DIOx只会产生一次中断(而不是三次),但使用函数
sx126x_get_irq_status()
读出的中断标志位irq_regs
有三个标志位,即Preamble detected、Header valid和Rx done。 - 如果第三个参数也配置了Preamble detected、Header valid和Rx done三个中断,则结果就是在接收这个包的过程中,DIOx会产生三次中断,所以中断处理函数会被调用三次,顺序是Preamble detected -> Header valid -> Rx done。
建议,在使用的时候,只配置希望用到的中断,将第二个和第三个参数配置成一样的,并且打开了哪些中断,哪些中断回调函数要有相应处理逻辑。这样做不仅可以避免代码逻辑漏洞,也可以减少MCU和radio的工作量。
sx126x_set_dio_irq_params( context,
SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_HEADER_ERROR | SX126X_IRQ_CRC_ERROR,
SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_HEADER_ERROR | SX126X_IRQ_CRC_ERROR,
SX126X_IRQ_NONE,
SX126X_IRQ_NONE );