RSS
people

Mazda MP3 Player — Продолжение 3

А вот и снова я!

Надеюсь, не заскучали тут без меня?

У меня есть уважительная причина — я отлавливал баги в софте плеера. И довольно таки много отловил.

В прошивке ПЛИС от Xlilinx заменил модуль выбора банков памяти на VHDL аналог, написанный с учетом всех особенностей адресации памяти и схемы.

В софте, соответственно, сделал изменения в системе Кучи (Heap), так как она напрямую связана с адресацией внешней памяти.

Теперь у меня используются все банки памяти.

Нашелся старый баг, заложенный мною же пару лет назад по тогдашней неопытности — в системе проигрывания MP3 файла использовался один из банков, и так как в то время я еще не совсем знал, на что мне потратить такое количество банков (30 штук), то я выбрал второй, с номером 1 (нумерация идет с 0, как мы помним). И вот он сейчас вылез боком, когда банк с этим номером использовался так же для хранения технической информации о всех файлах, найденных при сканировании дисков.

Система работала до первого проигрывания файла, играла первый файл хорошо, но при попытке выбора следующего — зависала и перезагружалась Вачдогом.

А не находился этот баг так долго потому, что я, по тогдашней неопытности, сделал выбор банка в обход интерфейса управления банками памяти, напрямую записывая в регистр банка его номер. Вот нам и урок на будущее — организовывайте доступ к какому либо модулю посредством интерфейса, и используйте только его!

В самом софте пока что сменил команды доступа к дисками с простых присваиваний на свои функции, которые пишут и читают не черех интерфейс внешней памяти контроллера, а путем прямого управления портами PORTA, PORTC и пинами N_RD, N_WR и ALE. На такой шаг замедления процесса чтения я пошел из-за того, что текущая прошивка CPLD немного подтормаживает при обработке адреса, и с момента выставления сигналов N_RD или N_WR проходит около 100 наносекунд, что очень много, так как нам надо успеть еще установить сигналы выбора дисков, немного подождать и потом установить сигналы чтения дисков. Если между этим двумя событиями не ждать, то что диск, что карточка, нас не поймут, и мы ничего не считаем с них. Временные параметры надо выдерживать.

Так вот. Пока мы это все выставляем тут и ждем, процессор нифига не ждет, надо сказать. И соответсвенно, ничего не считывает, или же очень малый процент считываний проходит успешно. На жестком диске это все как то еще работало, а вот карточка уже не успевала. И это была еще HS карточка, т.е высокоскоростная. А я попробовал поставить карточку помедленней — так ее даже не распознал плеер. Т.е. вообще никакой инфы не считалось.

По этому я пока что заменил обычные присваивания (которые процессор направляет на интерфейс внешней памяти) на процедуры прямого управления портами. Хоть и медленно, но работает все как часики. И все карточки и жесткий диск прекрасно считываются.

Но я, естественно, собираюсь оптимизировать прошивку cpld, не без помощи своего друга из Москвы, McSim, что бы увеличить скорость. А то уж больно медленно получается, чем было до этого.

А пока, как и обещал в прошлый раз, поговорим о методах работы с шиной M-Bus. О том, как считывать даный из нее, и как в нее писать что-либо.

Процессы чтения шины и записи в нее управляются посредством перерываний. Для чтения мы используем внешнее прерывание от ноги процессора, на которую предварительно завели сигнал с шины. А для записи — используем таймер.

Процесс чтения начинается по прерыванию по падающему фронту:

  1. /*
  2.  *   Receive interrupt
  3.  */
  4. SIGNAL(MBUS_RX_SIG_INT)
  5. {
  6.   u08 register bTimerVal;
  7.   if ( MBRProcess.bCanReceive )
  8.   {
  9.     switch ( MBRProcess.bBitRecState )
  10.     {
  11.       default:
  12.       case  MBR_WAITING:
  13.         if ( MBTProcess.bSending == 0 )
  14.         {
  15.           MBRProcess.bBitCounter = 0;
  16.           MBRProcess.bBitRecState++;
  17.         }
  18.       case MBR_FALLING:
  19.  
  20.         MBUS_RX_TCNT        = 0;
  21.         MBUS_RX_TIMER_TCCR  = MBUS_RX_PRESCALE;                      
  22.  
  23.         MBUS_RX_EICR &= ~MBUS_RX_INT_MSK;
  24.         MBUS_RX_EICR |=  MBUS_RX_INT_RIS;
  25.         MBRProcess.bBitRecState++;
  26.       break;
  27.  
  28.       case MBR_RISING:
  29.         bTimerVal = MBUS_RX_TCNT;
  30.  
  31.         MBRProcess.bBitsArray[ MBRProcess.bBitCounter / 8 ] &= ~(1 << ( 7 - (MBRProcess.bBitCounter % 8) ) );
  32.         if (
  33.              ( bTimerVal >= ( MBUS_TCNT_LOW_ONE - MBUS_TCNT_TOLERANCE ) ) &&
  34.              ( bTimerVal <= ( MBUS_TCNT_LOW_ONE + MBUS_TCNT_TOLERANCE ) )
  35.            )
  36.         {
  37.           MBRProcess.bBitsArray[ MBRProcess.bBitCounter / 8 ] |= (1 << ( 7 - (MBRProcess.bBitCounter % 8) ) );
  38.         }
  39.  
  40.         MBRProcess.bBitCounter++;                                    
  41.  
  42.         MBUS_RX_EICR &= ~MBUS_RX_INT_MSK;
  43.         MBUS_RX_EICR |=  MBUS_RX_INT_FAL;
  44.         MBRProcess.bBitRecState = MBR_FALLING;                        
  45.  
  46.         SWTLoad(SWT_MBUS_PACKET_TIMER, SWT_MBUS_PACKET_TIMER_VAL);
  47.       break;
  48.  
  49.       case MBR_DONT_RECEIVE:
  50.       break;
  51.     }
  52.  
  53.     if ( MBRProcess.bBitRecState >= MBR_MAX_STATES )
  54.     {
  55.       MBRProcess.bBitRecState = MBR_FALLING;
  56.     }
  57.     if ( MBRProcess.bBitCounter >= (MBUS_MAX_PACKET_LEN * 8) )
  58.     {
  59.       MBRProcess.bBitRecState = MBR_DONT_RECEIVE;
  60.       MBRProcess.bReceived    = 1;
  61.     }
  62.   }
  63. }

Разберем его по порядку.

В строке 188 мы проверяем, а надо ли нам воомще что-то принимать. Иногда бывают такие моменты, что лучше вообще ничего не слушать.

Если же мы решили, что нам все таки стоит послушать, что в мире творится, то далее смотрим, в каком месте находится наша система приема сообщений — в каком состоянии приема.

Всего их 4:

case MBR_WAITING: — Тут мы находимся, когда мы только только начали прием, или же мы уже приняли очередной бит, и ждем, когда же нам пошлют следующий, этакое междубитие. От этого пункта мы переходим к следующему без задержек.

case MBR_FALLING: — И так — пин упал в 0. Самое время засечь то самое время, сколько наш пин пробудет в этом состоянии 0.

Выставляем параметры таймера, обнуляем его счетчик и устанавливаем способ следуюго входа в наше прерывание, уже по восходящему фронту.

case MBR_RISING: — Тут начинается самое интересное — определение времени, которорое прошло между спадающим и восходящим фронтом по значению счетчика таймера. И в соответствии с длительностью уже выставляется текущий бит в 0 или 1. Далее мы увеличиваем счетчик принятых битов, ставим способ входа в наше прерывание опять по спадающему фронту, и ставим статус приема уже в MBR_FALLING.

И так по кругу.

Опытный читатель скажет, а как же мы определим, когда пакет закончился то? А то ведь так можно безконечно биты принимать, когда-то надо бы и определиться, что биты для этого пакета закончились и пошли уже биты следующего.

Правильно! Для этого в строке 227 стоит вызов функции SWTLoad (SWT_MBUS_PACKET_TIMER, SWT_MBUS_PACKET_TIMER_VAL);, которая устанавливает софтовый таймер на 6 милисекунд. Я тут пробовал разные значения и именно с этим получил самые хорошие результаты определения конца пакета.

Значит, таймер запустили, теперь надо бы его и обработать:

В аппаратном таймере происходит проверка нашего софтверного таймера:

  1.  if ( SWTFlag(SWT_MBUS_PACKET_TIMER) )
  2.  {
  3.    SWTClear(SWT_MBUS_PACKET_TIMER);
  4.    MBus_ReceivedPacket();
  5.  }

И, если софтверный таймер сработал, вызывается функция MBus_ReceivedPacket ();:

  1. /*
  2.  * Called on Receive timeout, sets a flag, that data received, and stops receive process
  3.  */
  4. void MBus_ReceivedPacket(void)
  5. {
  6.   MBUS_RX_TIMER_TCCR = 0;
  7.   MBRProcess.bBitRecState = MBR_DONT_RECEIVE;
  8.   MBRProcess.bReceived = 1;
  9.   SWTLoad( SWT_MBUS_ANSWER_TIMER, SWT_MBUS_ANSWER_AFTER_REQUEST_TIMER_VAL );
  10. }

в которой мы ставим наш приемник в состояние неприема — то самое 4-е состояние MBR_DONT_RECEIVE, вывешиваем флаг, что данные приняты, и запускаем уже другой таймер для задержки между приемом и отправкой ответа. Я опять же поэкспериментировал, и понял, что вот прямо сразу после того, как мы внимательно выслушали команду, лучше не болтать, а малость подождать, а то не поймут ведь.

Ну а далее все просто — в функции, которая у нас работает на каждом проходе основного цикла программы, мы проверяем этот флаг MBRProcess.bReceived на предмет наличия в нем 1, и обрабатываем данные.

Про то, как мы общаемся с шиной, я расскажу через часик, а то тут много текста получилось. До скорого!

P.S.:

Совсем забыл. Обновленные прошивки: mmp3p_v_01_01 и xilinx_v_01_01.

Вот.

10 комментариев к “Mazda MP3 Player — Продолжение 3”

  1. olzhan пишет:

    Прочитал с интересом но не хватает опыта работы с микроконтролерами. Вертится такой вопрос в голове — а намного ли проще будет устройство которое только общается по M-Bus с головным устройством и ключами управляет каким либо MP3 плэером, коих сейчас валом по 5 долларов за штуку. Т.е. не нужно будет думать за битрейт файла, работу с диском и т.д. Просто возможно такому новичку как я будет проще собрать такое устройство. X-Car Audiolink раздражает своей ценой (у нас порядка 400 долларов) и ограниченностью(тлеет надежда, что Вы разберетесь с CAN интерфейсом стандартного маздиного экранчика). Да и просто было бы приятней собрать своими руками)). СПАСИБО за проделанный труд!!!

  2. MasterAlexei пишет:

    Ого, это где ж у него такая цена? У нас на E-Bay можно за 99 евро найти.

    Просто управлять готовым плеером — думаю можно, но тогда надо найти способ подключиться к этому готовому плееру. Т.е. надо сам плеер препарировать, что не всегда является возможным, так как сейчас их компонуют довольно мелко, глаза поломаешь, пока найдешь, где что и откуда растет. Ну и потом это будет уже не монолитная конструкция, а набор проводов, торчащих в разные стороны, что в машине не приемлимо. Там вибрация постоянная, и что нибудь да отвалится. А так — думаю — можно и такое сделать. Про экран мазды — есть такая задумка, я ее все еще прорабатываю. Но тут все дело в том, что надо ставить свой контроллер между дисплеем и остальным миром. А моя машина еще на гарантии, хоть и частичной, и я не знаю, как к этому отнесется ОД (официальный диллер). Но я думаю в эту сторону. Как всегда — не хватает времени свободного на все.

  3. olzhan пишет:

    Цена такая на него близ города Актау, западный Казахстан. Надеюсь на Казахстан никаких обид не затаили?)) Оченно мне импонирует что земляки такие вещи творить способны. Я и сам с Алматы, токо Политех оканчивал. В качества плеера я в руках верчу ФМ модулятор китайского производства- платка 3см диаметром, питание 12В, разъемы под USB и SD, дисплейчик отображающий ID теги, три кнопки Play, Prev,Next-просто контакты. И всего 500тенге или 2 евро. Их не жалко и с десяток в экспериментах попортить. У головы есть ниша под MD проигрыватель прикрытая пластиковой пластинкой. Очень красиво получатся эту пластинку пропилить- будто у головы появились USB и SD разъемы. Вот такие фантазии. Спасибо!

  4. MasterAlexei пишет:

    Да, я тоже засматриваюсь на эту панельку, дмаю туда какой нить дисплейчик прикрутить, чтобы с моего плеера инфу показывал, а то номер дорожек и дисков не совпадает с тем, что на самом деле играет. Да и полгода пользования плеером показали, что при огромном количестве файлов и при наличии 50 плейлистов, забываешь, где что находится, какой трек в каком плейлисте, и в какую сторону крутить надо, чтобы добраться до нужной дорожки.

    Ну а подпаяться к кнопкам, думаю, труда не составит. Но голове все равно надо говорить, чего показывать. Т.е. дисплей самой мазды будет уже показывать не то, что играет на самом деле. И даже время не покажешь точно. Но сделать можно. Было бы желание.

  5. Rewerd пишет:

    Хотелось бы узнать как обстоят дела с чтеним МР3 по USB, если эта возможность предусмотренна!?

    Спасибо!

  6. MasterAlexei пишет:

    Смотря что имеется ввиду. Тот USB порт, что на плате — это обычный UART от меги. И на компе он как обычный USB< ->Serial конвертер распознается и на данный момент только для отладочной инфы используется.

    Идея была по этому порту заливать музыку на плеер, но это будет требовать много времени, так как скорости там не шибко шустрые, по этому я начал копать в сторону возможности копирования с CF карточки на винт. Но пока все так и осталось в зачаточном состоянии, так как время — оно такое. Вроде оно и есть, и как бы его и нет. В общем — как только — так сразу.

    Если же имеется ввиду возможность чтения файлов с USB накопителей, подключаемых к плееру — такой возможности не рассматривалось, по причине не поддерживаемости мегой USB-on-the-Go, или как там его. В общем — нету в этой меге USB встроенного, а самому реализовывать его не охота, да и есть вероятность, что в мегу он не влезет просто. Ну и железо подгонять придется.

  7. Rewerd пишет:

    Спасибо за скорый ответ!

    Ввиду имелся 2 вариант.

  8. Rewerd пишет:

    Жаль, хотел поддержку USB-stick в Mazde3 сделать.

    Будем копать дальше!

  9. MasterAlexei пишет:

    Для этого можно прикупить уже готовые девайсы типа USB-Link кажется или MP3-Link называются. На E-Bay их полно по 99 долларей.

  10. Mazda MP3 Player — Продолжение 4 | Fun Electronic пишет:

    [...] Analyzer V. 3.0marshallab on Мои инструменты: Logic Analyzer V. 3.0MasterAlexei on Mazda MP3 Player — Продолжение 3 МеткиБезопасность Выпайка Инструменты Кабель [...]

Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.