Важная информация

User Tag List

Страница 2 из 17 ПерваяПервая 123456 ... ПоследняяПоследняя
Показано с 11 по 20 из 163

Тема: ROM-плеер на ардуино

  1. #11
    Guru Аватар для svofski
    Регистрация
    20.06.2007
    Адрес
    С.-Петербург
    Сообщений
    4,105
    Спасибо Благодарностей отдано 
    772
    Спасибо Благодарностей получено 
    643
    Поблагодарили
    398 сообщений
    Mentioned
    22 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Improver Посмотреть сообщение
    мне показалось, что это будет слишком заморочено
    У страха глаза велики =) С таймерами самые невероятные вещи можно творить.

    Но на самом деле ради переносимости я бы правда отложил эту идею. Монотонность импульсов очень просто получить, если генерировать поток BPSK в виде битовых пар. А процедура вывода будет этот поток бит за битом брать, выводить и ждать. Тогда получается очень простая процедура с одним выводом и одной задержкой, которая не зависит от собственно значения очередного бита, фазы и, что самое интересное, даже от вида модуляции: все разновидности BPSK, BFSK, MFM, (m,n) RLL и GCR так представимы.
    Больше игр нет

  2. #12
    Master Аватар для Improver
    Регистрация
    06.02.2018
    Адрес
    г. Волгоград
    Сообщений
    970
    Спасибо Благодарностей отдано 
    417
    Спасибо Благодарностей получено 
    392
    Поблагодарили
    217 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Итак, продолжаем развивать проект...
    Подключил SD-картридер, схема подключениея такая, как в сообщении #19 zebest, только пока без кнопок и экрана. Да, и вывод сигнала остался на D3.

    Скетч


    В корень SD-карты положить файл "cybernoi.rom". Если карта не обнаружена, то подаётся сигнал 200Гц/100мс, если не обнаружен файл, то сигнал 200Гц/300мс.
    Код:
    /*
     * SD-картридер подключяется к выводам ардуино:
     ** MOSI  - D11
     ** MISO  - D12
     ** CLK   - D13
     ** CS    - D10
     *
     *  Выход - D3
     */
    #include <SD.h>
    
    File romFile;
    
    // Заголовок
    byte SB[27] = { 
      0x4E, 0x4F, 0x44, 0x49, 0x53, 0x43, 0x30, 0x30, // NODISK00
      0x31, 0x39, 0x30, 0x31, 0x31, 0x38,             // дата: 190118
      0x74, 0x65, 0x73, 0x74, 0x74, 0x70, 0x20, 0x20, // testtp.....
      0x20, 0x20, 0x20, 0x00, 0x00 };
    
    int p = 3; // номер пина, на который будет вывод сигнала
    
    void setup() //процедура setup
    {
      pinMode(p, OUTPUT); //объявляем пин как выход
      pinMode(10, OUTPUT);
    
      while (!SD.begin(10)){ // SD-карта готова?
        tone(p, 200, 100); // нет -- включаем на 200 Гц на 100 мс
        delay(3000);       // ждем 3 с
      } 
    }
    
    void loop() //процедура loop
    {
      tone(p, 500, 100); //включаем на 500 Гц на 100 мс
      delay(1000);       //ждем 1 с
    
      romFile = SD.open("cybernoi.rom"); // открываем файл
      if (romFile) {                     // открылся?
        byte BLs = 0x01;    // начальный блок
        unsigned int  Nbt = romFile.size();  // всего байтов
        byte BLe = Nbt/256; // всего блоков
        byte BLt;           // осталось блоков
        byte Nst;           // номер строки
        byte St;            // выводимый байт
    
        byte CSz = 0x00;    // контрольная сумма заголовка
        byte CSs = 0x00;    // контрольная сумма строки
        byte i;
        byte j;
    
        if (Nbt%256 != 0){  // корректировка количества блоков, если размер файла не кратен 256
          BLe++;
        } 
    
        // Начинаем вывод
        for (i=0; i<=3; i++){           // преамбула (4*(00H*25+55H*25))
          for (j=0; j<=24; j++){
            SendByte(0x00);
          }
          for (j=0; j<=24; j++){
            SendByte(0x55);
          }
        }  
    
        for (BLt=BLe; BLt>=1; BLt--){   // Вывод блоков данных
          CSz = BLs;
          CSz += BLe;
          CSz += BLt;
          for (j=0; j<=15; j++){        // 00h*16
            SendByte(0x00);
          }
          for (j=0; j<=3; j++){         // 55h*4
            SendByte(0x55);
          }
          SendByte(0xE6);               // E6h*1
          for (j=0; j<=3; j++){         // 00h*4
            SendByte(0x00);
          }
    
          for (j=0; j<=26; j++){        // заголовок блока
            CSz += SB[j];
            SendByte(SB[j]);
          }
          SendByte(BLs);                // начальный блок
          SendByte(BLe);                // конечный блок
          SendByte(BLt);                // осталось блоков
          SendByte(CSz);                // контр.сумма заголовка
    
          for (Nst=0x80; Nst<=0x87; Nst++){   // вывод строк (8 шт.)
            for (j=0; j<=3; j++){       // 00h*4
              SendByte(0x00);
            }
            SendByte(0xE6);             // E6h*1
            CSs = Nst;
            SendByte(Nst);              // номер строки
            CSs += CSz;
            SendByte(CSz);              // контр.сумма заголовка
    
            for (j=0; j<=31; j++){      // собственно, строка данных
              if (Nbt > 0){          // ещё есть данные?
                St = romFile.read(); // читаем очередной байт из файла
                Nbt--;
              } 
              else {                 // нет -- дополняем нулями
                St = 0x00;
              }
              CSs += St;
              SendByte(St);
            }
            SendByte(CSs);              // контр.сумма строки
          }  
        }
    
        for (j=0; j<=15; j++){          // 00h*16 -- завершение вывода программы (?)
          SendByte(0x00);
        }
        // close the file:
        romFile.close();
      }
      else {      
        tone(p, 200, 300); // нет файла -- включаем на 200 Гц на 300 мс
      }
      delay(15000);   // ждем 15 с
    }
    
    void SendByte(byte SBt){          // Подпрограмма вывода байта
      byte Pd=PORTD;
      byte i=8;
      do{                 // Выводим биты начиная со старшего
        i--;
        if ((bitRead(Pd, p))^(bitRead(SBt, i))){ // Если состояние порта и выводимый бит разные
          Pd ^= (1 << p); // инвертируем бит в позиции p=3
          PORTD = Pd;     // вывод в порт p
        }
        else{
          delayMicroseconds(16); // Задержка для выравнивания длительности сигнала
        }
        delayMicroseconds(256);   // Задержка первого полупериода сигнала
        Pd ^= (1 << p);   // инвертируем бит в позиции p
        PORTD = Pd;       // вывод в порт p
        delayMicroseconds(256);   // Задержка второго полупериода сигнала
      } 
      while (i>0);
    }
    [свернуть]

    Для проверки взял один из самых больших ROM-файлов, игру Cybernoid, на выгрузку ушло примерно 4 минуты. Всё, вроде, отработало здорово, но при распознавании в wav2rom вылезло 45 ошибок. :-( Причём все ошибки в первом байте блока (не каждого -- в 45 из 159 блоков):
    Нажмите на изображение для увеличения. 

Название:	20_diff.jpg 
Просмотров:	326 
Размер:	75.5 Кб 
ID:	64163

    Просмотр сигнала в той же программе выявил ошибку:
    Нажмите на изображение для увеличения. 

Название:	20.jpg 
Просмотров:	321 
Размер:	81.0 Кб 
ID:	64164

    Где-то возникают тормоза -- или прерывание срабатывает, или чтение с карты тормозит... Причём эти ошибки есть даже если выгружаемая программа короткая, например тот же тест техпрогона. В общем, надо ещё подумать...

    Вот скетч в архиве: Test_TP_fromSD.ino.zip, WAV-файл не выкладываю -- нет смысла...

    - - - Добавлено - - -

    Цитата Сообщение от svofski Посмотреть сообщение
    У страха глаза велики =) С таймерами самые невероятные вещи можно творить.

    Но на самом деле ради переносимости я бы правда отложил эту идею.
    Да, оставим на потом. А с другой стороны, с выводом без всяких таймеров легко справлялся проц КР580ВМ80А -- и ардуина тоже должна справится. :-)

  3. #13
    Guru Аватар для svofski
    Регистрация
    20.06.2007
    Адрес
    С.-Петербург
    Сообщений
    4,105
    Спасибо Благодарностей отдано 
    772
    Спасибо Благодарностей получено 
    643
    Поблагодарили
    398 сообщений
    Mentioned
    22 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Код:
    St = romFile.read(); // читаем очередной байт из файла
    Предполагаю, что эта процедура берет очередной байт из буфера, а когда буфер заканчивается, читает целиком следующий сектор, или несколько, если надо свериться с FAT, что и вызывает задержку.

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

  4. #14
    Master Аватар для Improver
    Регистрация
    06.02.2018
    Адрес
    г. Волгоград
    Сообщений
    970
    Спасибо Благодарностей отдано 
    417
    Спасибо Благодарностей получено 
    392
    Поблагодарили
    217 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    svofski, я сейчас попробовал сделать предварительную считку байта до того, как блок начал выводиться, при этом задержка вылезла в заголовок. Если там допустима некоторая рассинхронизация, то это решение... Как я понимаю, задержка может происходить до начала заголовка блока (00h*16, 55h*4...)?

  5. #15
    Guru Аватар для svofski
    Регистрация
    20.06.2007
    Адрес
    С.-Петербург
    Сообщений
    4,105
    Спасибо Благодарностей отдано 
    772
    Спасибо Благодарностей получено 
    643
    Поблагодарили
    398 сообщений
    Mentioned
    22 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Это мое предположение, да. По идее после последнего байта любого блока можно сделать безболезненную паузу. Не знаю, как на самом деле на это реагирует загрузчик.

    Параллельно я бы все-таки поинтересовался недрами драйвера, чтобы научиться читать поток без задержек. Это пригодится для форматов без блоков.
    Больше игр нет

  6. #16
    Master Аватар для Improver
    Регистрация
    06.02.2018
    Адрес
    г. Волгоград
    Сообщений
    970
    Спасибо Благодарностей отдано 
    417
    Спасибо Благодарностей получено 
    392
    Поблагодарили
    217 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    ivagor, svofski, можете протестить на железе (или эмуляторах) такой вариант: TestWAV25.7z?
    Это всё тот же тест техпрогона, но с sd-карты. В wav2rom он (и киберноид тоже) распознаются без ошибок, но в тесте есть два фриза, перед первым блоком и ближе к концу, наверно после второго или третьего блока:
    Нажмите на изображение для увеличения. 

Название:	25.jpg 
Просмотров:	287 
Размер:	82.0 Кб 
ID:	64168

  7. #16
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  8. #17
    Veteran
    Регистрация
    22.02.2014
    Адрес
    г. Курган
    Сообщений
    1,653
    Спасибо Благодарностей отдано 
    214
    Спасибо Благодарностей получено 
    301
    Поблагодарили
    212 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

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

  9. #18
    Guru Аватар для svofski
    Регистрация
    20.06.2007
    Адрес
    С.-Петербург
    Сообщений
    4,105
    Спасибо Благодарностей отдано 
    772
    Спасибо Благодарностей получено 
    643
    Поблагодарили
    398 сообщений
    Mentioned
    22 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    У меня сейчас место расчищено для других дел, так что реал ждет своей очереди на полке. В эмулятор грузится хорошо.

    - - - Добавлено - - -

    В Тапире видно пропуски:

    Для стандартного загрузчика безболезненно можно сделать полупериод 5. Это будет не огромное ускорение, то все же.
    Больше игр нет

  10. #19
    Master Аватар для Improver
    Регистрация
    06.02.2018
    Адрес
    г. Волгоград
    Сообщений
    970
    Спасибо Благодарностей отдано 
    417
    Спасибо Благодарностей получено 
    392
    Поблагодарили
    217 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Использованием библиотеки SdFat из проекта TZXDuino и переделкой подпрограммы вывода байта SendByte удалось сократить провалы в передаче сигнала раза в полтора, но всё равно она сейчас составляет примерно шесть полупериодов сигнала. Пробовал предварительно вычитывать 256 байт (1 блок) в буфер, но толку от этого нет -- всё равно задержки...
    Вот что имеем в последней версии программы:

    Скетч

    Код:
    /*
     * SD-картридер подключяется к выводам ардуино:
     ** MOSI  - D11
     ** MISO  - D12
     ** CLK   - D13
     ** CS    - D10
     *
     *  Выход - D3
     */
    #include <SdFat.h>
    
    SdFat sd;
    SdFile romFile;
    
    // Заголовок
    byte SB[27] = { 
      0x4E, 0x4F, 0x44, 0x49, 0x53, 0x43, 0x30, 0x30, // NODISK00
      0x31, 0x34, 0x30, 0x32, 0x31, 0x38,             // дата: 140218
      0x74, 0x65, 0x73, 0x74, 0x74, 0x70, 0x20, 0x20, // testtp.....
      0x20, 0x20, 0x20, 0x00, 0x00 };
    
    int p = 3; // номер пина, на который будет вывод сигнала
    unsigned long Tzd = 0; // переменная для расчёта задержки
    const int Tpp = 256; // Длительность задержки сигнала в микросекундах (один полупериод)
    
    void setup() //процедура setup
    {
      pinMode(p, OUTPUT); //объявляем пин как выход
      pinMode(10, OUTPUT);
    
      while (!sd.begin(10,SPI_FULL_SPEED)){ // SD-карта готова?
        tone(p, 200, 100); // нет -- включаем на 200 Гц на 100 мс
        delay(3000);       // ждем 3 с
      }
      sd.chdir();          // устанавливаем корневую директорию SD
    }
    
    void loop() //процедура loop
    {
      tone(p, 500, 100); //включаем на 500 Гц на 100 мс
      delay(1000);       //ждем 1 с
    
      if (romFile.open("cybernoi.rom",O_READ)) { // открываем файл. Открылся?
        byte BLs = 0x01;    // начальный блок
        unsigned int Nbt = romFile.fileSize();  // всего байт
        byte BLe = Nbt/256; // всего блоков
        byte BLt;           // осталось блоков
        byte Nst;           // номер строки
        byte St;            // выводимый байт
    
        byte CSz = 0x00;    // контрольная сумма заголовка
        byte CSs = 0x00;    // контрольная сумма строки
        byte i;
        byte j;
    
        if (Nbt%256 != 0){  // корректировка количества блоков, если размер файла не кратен 256
          BLe++;
        } 
    
        // Начинаем вывод
        for (i=0; i<=3; i++){           // преамбула (4*(00H*25+55H*25))
          for (j=0; j<=24; j++){
            SendByte(0x00);
          }
          for (j=0; j<=24; j++){
            SendByte(0x55);
          }
        }  
    
        for (BLt=BLe; BLt>=1; BLt--){   // Вывод блоков данных
          CSz = BLs;
          CSz += BLe;
          CSz += BLt;
          // упреждающее чтение первого байта блока данных с карты (он всегда есть)
          St = romFile.read(); // читаем байт из файла
          Nbt--;
    
          for (j=0; j<=15; j++){        // 00h*16
            SendByte(0x00);
          }
          for (j=0; j<=3; j++){         // 55h*4
            SendByte(0x55);
          }
          SendByte(0xE6);               // E6h*1
          for (j=0; j<=3; j++){         // 00h*4
            SendByte(0x00);
          }
    
          for (j=0; j<=26; j++){        // заголовок блока
            CSz += SB[j];
            SendByte(SB[j]);
          }
          SendByte(BLs);                // начальный блок
          SendByte(BLe);                // конечный блок
          SendByte(BLt);                // осталось блоков
          SendByte(CSz);                // контр.сумма заголовка
    
          for (Nst=0x80; Nst<=0x87; Nst++){   // вывод строк (8 шт.)
            for (j=0; j<=3; j++){       // 00h*4
              SendByte(0x00);
            }
            SendByte(0xE6);             // E6h*1
            CSs = Nst;
            SendByte(Nst);              // номер строки
            CSs += CSz;
            SendByte(CSz);              // контр.сумма заголовка
    
            CSs += St;                // начинаем вывод строки данных
            SendByte(St);             // предварительно считанный байт
    
            for (j=0; j<=30; j++){      // остальные 31 байт
              if (Nbt > 0){             // ещё есть данные?
                St = romFile.read();    // читаем очередной байт из файла
                Nbt--;
              }
              else {                    // нет -- дополняем нулями
                St = 0x00;
              }
              SendByte(St);             // передаём считанный байт
              CSs += St;
            }
            SendByte(CSs);              // контр.сумма строки
            if (Nst !=0x87) {
              if (Nbt > 0){             // ещё есть данные?
                St = romFile.read();    // читаем очередной байт из файла
                Nbt--;
              }
              else {                    // нет -- дополняем нулями
                St = 0x00;
              }
            }
          }  
        }
    
        for (j=0; j<=15; j++){          // 00h*16 -- завершение вывода программы (?)
          SendByte(0x00);
        }
        // close the file:
        romFile.close();
      }
      else {      
        tone(p, 200, 300); // нет файла -- включаем на 200 Гц на 300 мс
      }
      delay(15000);   // ждем 15 с
    }
    
    void SendByte(byte SBt){          // Подпрограмма вывода байта
      byte Pd=PORTD;
      byte i=8;
      do{                 // Выводим биты начиная со старшего
        i--;
        Tzd = micros() - Tzd;           // Вычисляем, какая была задержка
        if (Tzd < Tpp) {                // Если прошло времени меньше, чем установленная задержка
          delayMicroseconds(Tpp - Tzd); // Задержка второго полупериода сигнала (предыдущего)
        }
        Pd ^= (1 << p);   // инвертируем бит в позиции p(=3)
        PORTD = Pd;       // вывод в порт p
        delayMicroseconds(Tpp);         // Задержка первого полупериода сигнала
        Tzd = micros();                 // начало отсчёта длительности задержки
        if ((bitRead(Pd, p))^(bitRead(SBt, i))){ // Если состояние порта и выводимый бит разные
          Pd ^= (1 << p); // инвертируем бит в позиции p
          PORTD = Pd;     // вывод в порт p
        }
      } 
      while (i>0);
    }
    [свернуть]

    И он же вместе с библиотекой в архиве: TestTP_fromSD_3.zip
    WAV-ка с примером вывода: TestWAV29.7z
    Будем оптимизировать дальше... :-)

  11. #20
    Guru Аватар для svofski
    Регистрация
    20.06.2007
    Адрес
    С.-Петербург
    Сообщений
    4,105
    Спасибо Благодарностей отдано 
    772
    Спасибо Благодарностей получено 
    643
    Поблагодарили
    398 сообщений
    Mentioned
    22 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    По-моему тут оптимизировать уже нечего, в рамках принятой концепции все на месте. Чтобы избавиться от задержек совсем, надо менять концепцию.

    Чтобы было максимально просто и не заморачиваться на специфическое железо, я бы сделал так:

    * Создаются 2 пинг-понг буфера. Один на запись, второй на чтение. В идеале конечно надо библиотеке SD объяснить, что читать надо прямо в них, а не копировать по байту. Иначе очень жирно будет буферов, что для AVR особенно критично.

    * Прерывание от таймера настраивается на полупериод кассетного бита. Оно выводит один полубит и сдвигает указатель на следующий полубит. Когда кончается бит, на следующий бит, когда кончается байт, на следующий байт. Когда закончится буфер А, переключается на чтение буфера Б и ставит флажок "нужен буфер".

    * Основной цикл слушает флажок "нужен буфер" и запускает чтение буфера А, пока выводится Б и наоборот.
    Больше игр нет

Страница 2 из 17 ПерваяПервая 123456 ... ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Портативный AY плеер.
    от Руслан в разделе Звук
    Ответов: 1
    Последнее: 16.04.2014, 08:46
  2. Service rom + 128 basic rom
    от VELESOFT в разделе Оси
    Ответов: 1
    Последнее: 24.03.2013, 04:48
  3. Плеер для pt 3
    от Руслан в разделе Музыка
    Ответов: 25
    Последнее: 14.08.2012, 19:25
  4. Advanced ROM Manager (ROM Switvcher + Prof. ROM)
    от Alex_NEMO в разделе Память
    Ответов: 4
    Последнее: 04.10.2010, 11:43
  5. AY плеер
    от newart в разделе Звук
    Ответов: 19
    Последнее: 20.07.2006, 00:03

Метки этой темы

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •