Недавно столкнулся с неприятной проблемой, когда по непонятной для меня причине при интенсивной работе на передачу не устанавливался бит MRDY регистра CAN_MSRx в передающем CAN-mailbox (поле MOT в регистре CAN_MMRx установлено в значение 3). Таким образом, ящик становится заблокированным, и его нельзя использовать на передачу.
После долгих экспериментов выяснилось, что нельзя слишком часто опрашивать чтением регистр статуса ящика CAN_MSRx. Например, следующий код при слишком интенсивной передаче через один ящик приводит к бесконечной блокировке этого ящика, бит MRDY навсегда переходит в 0:
void SendCAN (TCAN_msg* msg)
{
// Передача через ящик 4:
AT91PS_CAN_MB pmb = AT91C_BASE_CAN_MB0+4;
// Бесконечный цикл ожидания освобождения ящика с опросом бита MRDY
// в регистре CAN_MSR4:
while (0 == (AT91C_CAN_MRDY & AT91F_CAN_GetMessageStatus(pmb)));
// Ящик освободился (MRDY==1), передача пакета msg:
AT91F_InitMailboxRegisters(pmb,
AT91C_CAN_MOT_TX,
0x3F,
((u32)msg->msg_adress << 18),
msg->candata.d32[0],
msg->candata.d32[1],
((u32)msg->msg_DLC << 16) |AT91C_CAN_MTCR);
}
Если показанная выше процедура SendCAN используется интенсивно, то в цикле ожидания while происходит бесконечное зависание. Бит MRDY после пяти-шести идущих друг за другом (без паузы) передач наглухо оказывается в лог. 0, сигнализируя о занятости ящика. Явный глюк, потому что в документации эта проблема не описана.
Исправить проблему может следующий код, с ним бит MRDY устанавливается нормально:
bool SendCAN (TCAN_msg* msg)
{
AT91PS_CAN_MB pmb = AT91C_BASE_CAN_MB0+4;
// Проверка освобождения ящика 4:
if (AT91C_CAN_MRDY & AT91F_CAN_GetMessageStatus(pmb))
{
//Ящик 4 освободился (MRDY==1), передача пакета msg:
AT91F_InitMailboxRegisters(pmb,
AT91C_CAN_MOT_TX,
0x3F,
((u32)msg->msg_adress << 18),
msg->candata.d32[0],
msg->candata.d32[1],
((u32)msg->msg_DLC << 16) |AT91C_CAN_MTCR);
return true;
}
else
return false;
}
Функция SendCAN может вызываться во внешнем цикле. Возвращенный 0 сигнализирует о неудачной передаче, когда попытка передачи должна быть повторена, а лог. 1 означает, что пакет был успешно передан.
[Ссылки]
1. AT91SAM7X: контроллер CAN. 2. Интерфейс CAN в микроконтроллере ARM AT91SAM7X256. |