Esta pregunta fue reescrita para eliminar varias actualizaciones y mejorar la claridad.
Tengo un MCU basado en Cortex M3 (y bastante oscuro). Tengo un proyecto bastante grande, escrito en C ++, en Keil MDK5 con compilador armcc.
Tengo esta función:
bool CanHandle::sendMsg(CanMsg & msg)
{
bool result = false; // <--------- problematic line
CAN_TxMsgTypeDef txMsg;
if (format == FrameFormat::EXTENDED)
{
txMsg.IDE = CAN_ID_EXT;
}
else
{
txMsg.IDE = CAN_ID_STD;
}
ENTER_CRITICAL_SECTION();
uint32_t bufN = CAN_GetEmptyTransferBuffer(set.mdrCan);
if (bufN != CAN_BUFFER_NUMBER)
{
CAN_Transmit(set.mdrCan, bufN, &txMsg);
isTxQueueFull = false;
}
else
{
isTxQueueFull = true;
result = false;
}
LEAVE_CRITICAL_SECTION();
return result;
}
Cuando compilo con -O1, el compilador produce esta lista de ensamblados para él:
0x0800068C E92D41FF PUSH {r0-r8,lr}
0x08000690 4604 MOV r4,r0
0x08000692 2700 MOVS r7,#0x00
0x08000694 7A20 LDRB r0,[r4,#0x08]
0x08000696 2600 MOVS r6,#0x00
0x08000698 F04F0801 MOV r8,#0x01
0x0800069C 2801 CMP r0,#0x01
0x0800069E D013 BEQ 0x080006C8
0x080006A0 F88D6005 STRB r6,[sp,#0x05]
0x080006A4 4860 LDR r0,[pc,#384] ; @0x08000828
0x080006A6 6800 LDR r0,[r0,#0x00]
0x080006A8 F3C00508 UBFX r5,r0,#0,#9
0x080006AC F8D401FC LDR r0,[r4,#0x1FC]
0x080006B0 F000FBCA BL.W CAN_GetEmptyTransferBuffer (0x08000E48)
0x080006B4 4601 MOV r1,r0
0x080006B6 2920 CMP r1,#0x20
0x080006B8 D009 BEQ 0x080006CE
0x080006BA 466A MOV r2,sp
0x080006BC F8D401FC LDR r0,[r4,#0x1FC]
0x080006C0 F000FBC4 BL.W CAN_Transmit (0x08000E4C)
0x080006C4 7266 STRB r6,[r4,#0x09]
0x080006C6 E004 B 0x080006D2
0x080006C8 F88D8005 STRB r8,[sp,#0x05]
0x080006CC E7EA B 0x080006A4
0x080006CE F8848009 STRB r8,[r4,#0x09]
0x080006D2 B004 ADD sp,sp,#0x10
0x080006D4 4638 MOV r0,r7
0x080006D6 E8BD81F0 POP {r4-r8,pc}
Y aquí está lo gracioso: cuando trato de pasar por encima de la línea bool result = false;
, tengo una falla fuerte con el conjunto de indicadores UNDEFINSTR. La PC recuperada de la pila muestra alguna dirección inexistente.
Pero , y aquí está la cosa realmente misteriosa: si paso por encima del ensamblaje, o si paso por el código C o si establece un punto de interrupción en la línea 2 y presiona Ejecutar, ¡todo está bien! No hay falla dura, el programa se ejecuta desde allí. Si compilo con -O0 o hago un resultado volátil, el compilador produce un ensamblaje diferente y no se produce una falla. Intenté usar diferentes versiones de compilador o IDE: el problema persiste.
La ejecución de este programa sin depurador no produce fallas.
La depuración en el simulador no produce fallas, pero pasar sobre esa línea en particular no pasa, hace que el programa se ejecute indefinidamente.
Esta función se llama desde main, por lo que, después de su finalización, hay solo while (1). Creo que no hay ningún problema en el código externo.
El código de la función ahora está al mínimo, si elimino cualquier línea, literalmente cualquier línea, el problema desaparece. Anteriormente publiqué varias suposiciones erróneas, las eliminé por ahora. No puedo precisar ninguna instrucción o dirección particular que produzca fallas. Todas las llamadas de función allí son maniquíes, vuelven inmediatamente. Las macros de CRITICAL_SECTION no producen secciones críticas en absoluto, pero algo tiene que estar en esas líneas o no ocurre ninguna falla.
Literalmente no tengo idea de cómo puede suceder eso. No sé cómo funciona exactamente el depurador, ¿cuál es la diferencia entre detenerse y establecer un punto de interrupción y pulsar "ejecutar"?