MCU code fault analysis

记录在MCU出现未按照预期工作的解决方案或思路

MCU发送一帧数据后,立刻又收到一个字节数据(GD32E230)

一、测试条件、故障现象、复现过程

  1. 在bootloader中,使用CDBus协议。使用上位机多次读写会高概率出现舵机不响应情况
  2. 舵机串口原理图,使用USART0 PA9引脚

  1. 串口初始化时配置为TX RX都使能;切换发送和接收时只切换485的DE RE引脚上的电平:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define RXMODE()      gpio_bit_reset(GPIOA,GPIO_PIN_0)
#define TXMODE() gpio_bit_set(GPIOA,GPIO_PIN_0)
void serial_init(void)
{
USART_CTL0(USART0) &= ~USART_CTL0_WL;
USART_BAUD(USART0) = 0x271;
USART_CTL2(USART0) |= USART_CTL2_HDEN;
USART_CTL0(USART0) |= USART_CTL0_TEN | USART_CTL0_REN | USART_CTL0_UEN;
}

void uartSend(uint8_t *buf, uint8_t len)
{
for (uint8_t i = 0; i < len; i++)
{
USART_TDATA(USART0) = *buf++;
while (RESET == usart_flag_get(USART0, USART_FLAG_TC));
usart_flag_clear(USART0, USART_FLAG_TC);
}
}

void uartRecive(void)
{
while(1)
{
if (usart_flag_get(USART0, USART_FLAG_RBNE))
{
// recive uasrt data

// to do responed
TXMODE();
uartSend();
RXMODE();
}
}
}

二、分析故障

  1. 调试时发现:MCU回复主机命令后,可以看到,MCU又接收到了一个字节的数据(此时主机并没有发送数据),这个字节的数据和MCU自己发送的第一个字节相同

  1. 在GD32e23x用户手册中写明了:通讯冲突由软件处理

  1. 根据手册我推测:MCU初始化串口时同时开启了TX 和 RX,在MCU回包时RX没有关闭,导致MCU把TX的数据认为时RX的数据,由于RX的缓冲区RDATA只有一个深度,仅在被MCU读出后才能接收新的数据,因此当MCU发送完所有数据后,MCU判断到有新的串口数据。

四、解决故障

  1. MCU串口初始化时进开启RX
  2. MCU在回包时打开TX,关闭RX
  3. MCU在回包结束后关闭TX,打开RX
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define RXMODE()    \
do { \
gpio_bit_reset(GPIOA,GPIO_PIN_0); \
usart_transmit_config(USART0, USART_TRANSMIT_DISABLE); \
usart_receive_config(USART0, USART_RECEIVE_ENABLE); \
}while(0)
#define TXMODE() \
do { \
gpio_bit_set(GPIOA,GPIO_PIN_0); \
usart_receive_config(USART0, USART_RECEIVE_DISABLE); \
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); \
}while(0)

void serial_init(void)
{
USART_CTL0(USART0) &= ~USART_CTL0_WL;
USART_BAUD(USART0) = 0x271;
USART_CTL2(USART0) |= USART_CTL2_HDEN;
USART_CTL0(USART0) |= USART_CTL0_REN | USART_CTL0_UEN;
}

农业无刷电机,快速下上电,出现电机不工作(AT32F413)

一、测试条件和故障现象

  1. 电源网络:220V—->24V–DCDC–>9V–LDO–>5V/3.3V
  2. 上电,客户使用脚本让电机在允许范围内随机高频运动。
  3. 突然拍下急停(断开220V—->24V链路),立刻恢复,电机无法通讯,无法工作。

二、复现过程

  1. 用python写脚本让电机在允许范围内随机高频运动。串口通过RS-485连接程控电源。在一定时间内随机关闭电源,然后立刻开启电源。无法复现。
  2. 手动将电源电压调到0V。开启电源,然后1V/step增加电压,逐渐到9V。电机无法通讯。

三、分析故障

  1. 使用示波器抓晶振,不起振。重新给复位信号,晶振起振,电机工作正常。
  2. 在system_init函数中增加IO toggle(不要太多次,会导致电压稳定,故障消失)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void SystemInit (void)
{

#if IODEBUG
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);

gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_10;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
gpio_bits_reset(GPIOB, GPIO_PINS_10);
#endif



#if defined (__FPU_USED) && (__FPU_USED == 1U)
SCB->CPACR |= ((3U << 10U * 2U) | /* set cp10 full access */
(3U << 11U * 2U) ); /* set cp11 full access */
#endif

/* reset the crm clock configuration to the default reset state(for debug purpose) */
/* set hicken bit */
CRM->ctrl_bit.hicken = TRUE;

/* wait hick stable */
while(CRM->ctrl_bit.hickstbl != SET);

/* hick used as system clock */
CRM->cfg_bit.sclksel = CRM_SCLK_HICK;

#if IODEBUG
gpio_bits_toggle(GPIOB, GPIO_PINS_10);
gpio_bits_toggle(GPIOB, GPIO_PINS_10);
#endif
/* wait sclk switch status */
while(CRM->cfg_bit.sclksts != CRM_SCLK_HICK);
#if IODEBUG
gpio_bits_toggle(GPIOB, GPIO_PINS_10);
gpio_bits_toggle(GPIOB, GPIO_PINS_10);
#endif

/* reset hexten, hextbyps, cfden and pllen bits */
CRM->ctrl &= ~(0x010D0000U);

/* reset cfg register, include sclk switch, ahbdiv, apb1div, apb2div, adcdiv,
clkout pllrcs, pllhextdiv, pllmult, usbdiv and pllrange bits */
CRM->cfg = 0;

/* reset clkout[3], usbbufs, hickdiv, clkoutdiv */
CRM->misc1 = 0;

/* disable all interrupts enable and clear pending bits */
CRM->clkint = 0x009F0000;

#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* vector table relocation in internal sram. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* vector table relocation in internal flash. */
#endif
}
  1. MCU卡在了while(CRM->cfg_bit.sclksts != CRM_SCLK_HICK);

四、解决故障

  1. 由于MCU在system_init 阶段就已经不工作,因此需要在system_init启动阶段就开启看门狗
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void SystemInit (void)
{
if(crm_flag_get(CRM_WDT_RESET_FLAG) != RESET)
crm_flag_clear(CRM_WDT_RESET_FLAG);
wdt_register_write_enable(TRUE);
wdt_divider_set(WDT_CLK_DIV_4);
wdt_reload_value_set(1000 - 1);
wdt_counter_reload();
wdt_enable();

#if defined (__FPU_USED) && (__FPU_USED == 1U)
SCB->CPACR |= ((3U << 10U * 2U) | /* set cp10 full access */
(3U << 11U * 2U) ); /* set cp11 full access */
#endif

/* reset the crm clock configuration to the default reset state(for debug purpose) */
/* set hicken bit */
CRM->ctrl_bit.hicken = TRUE;

/* wait hick stable */
while(CRM->ctrl_bit.hickstbl != SET);

/* hick used as system clock */
CRM->cfg_bit.sclksel = CRM_SCLK_HICK;

/* wait sclk switch status */
while(CRM->cfg_bit.sclksts != CRM_SCLK_HICK);

/* reset hexten, hextbyps, cfden and pllen bits */
CRM->ctrl &= ~(0x010D0000U);

/* reset cfg register, include sclk switch, ahbdiv, apb1div, apb2div, adcdiv,
clkout pllrcs, pllhextdiv, pllmult, usbdiv and pllrange bits */
CRM->cfg = 0;

/* reset clkout[3], usbbufs, hickdiv, clkoutdiv */
CRM->misc1 = 0;

/* disable all interrupts enable and clear pending bits */
CRM->clkint = 0x009F0000;

#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* vector table relocation in internal sram. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* vector table relocation in internal flash. */
#endif
}