Программирование ARM: решение проблем, FAQ AT91SAM7: проблема установки бита MRDY в регистре статуса CAN mailbox Wed, October 17 2018  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


AT91SAM7: проблема установки бита MRDY в регистре статуса CAN mailbox Печать
Добавил(а) microsin   

Недавно столкнулся с неприятной проблемой, когда по непонятной для меня причине при интенсивной работе на передачу не устанавливался бит 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.

 

Добавить комментарий


Защитный код
Обновить

Top of Page