PDA

Просмотр полной версии : Чтение TAP файлов ZX-Spectrum на базе STM32F407



san010101
28.09.2017, 07:29
Всем привет!
Решил для изучения STM32 запастись платой STM32F407G-DISC1
описание http://www.st.com/en/evaluation-tools/stm32f4discovery.html
http://www.st.com/content/ccc/fragment/product_related/rpn_information/board_photo/17/e9/78/47/7c/f4/42/e1/stm32f4_discovery.jpg/files/stm32f4_discovery.jpg/_jcr_content/translations/en.stm32f4_discovery.jpg

Демонстрация воспроизведения файла формата tap

https://youtu.be/Ju2uTypidPs

Изначально информация взята из
http://zx-info.ru/?rc=12&id=5

HardWareMan
28.09.2017, 09:12
А tzx осилил? А я такое баловался на MikroE, у меня есть Mikromedia (https://shop.mikroe.com/mikromedia-3-stm32f4) и Mikromedia+ (https://shop.mikroe.com/mikromedia-4-stm32f4)

san010101
28.09.2017, 09:25
пока нет, с tap не все разобрал. В планах потом запись сделать и РК86 разобрать.
Сейчас нет возможности даже протестировать.

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

Может есть эмулятор с возможностью физического подключения магнитофона. Тогда можно потестить на предмет загрузки файла.

s_kosorev
28.09.2017, 09:30
звучит металлически, поставить low pass фильтр

san010101
28.09.2017, 09:34
это для теста, звук через пьезо пищалку. По хорошему надо осциллографом проверить, но пока нет возможности.

s_kosorev
28.09.2017, 09:35
это для теста, звук через пьезо пищалку
а.. ок

creator
28.09.2017, 10:06
А tzx осилил?
Вроде пока что TZX умеет только TZXDuino (https://arduitape.blogspot.ru/2018/03/trying-to-make-firmware-editing-more.html). Причём умеет всякие спидлоки и прочие извращения. Гоняю, прикольно.

san010101
28.09.2017, 11:14
http://www.projectavr.com/avr-projects/
Нашел вот этот проект. Я так понимаю это клон.

McKlaud
28.09.2017, 19:05
http://arduitapemarkii.blogspot.co.uk/?m=1

san010101
29.09.2017, 06:22
Отрабатываю алгоритм считывания tap файла.
Вся работа по чтению производится в прерывании таймера, именно там генерируются частоты для пилот тонов и нуля-еденицы.
Хотел для обучения опробовать с RTOS но там встала проблема,
как реализовать обработку прерываний таймера что бы генерировать нужные частоты.
В RTOS не работают прерывания таймера.

HardWareMan
29.09.2017, 06:49
Чойто не работает то? Используй таймер а не SYSTICK, т.к. последний забирается самой RTOS для организации многозадачности.

san010101
29.09.2017, 07:07
это понятно, но на практике не прокатывает

file stm32f4xx_it.c
brief Interrupt Service Routines.
в этом файле у меня вся обработка по таймеру.

Делаю тоже с RTOS и прерывания не работают, как будто их лочит RTOS

HardWareMan
29.09.2017, 09:06
Ну вот у меня в проекте есть RTOS. Я делаю так:

// Настройка таймера
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );
// Запуск таймера TIM3 если он стоял (зависимость модуля от таймера)
TIM3->PSC = 0x00A7; TIM3->ARR = 0xFFFF; TIM3->CCMR1 = 0x0000; TIM3->CCMR2 = 0x3131;
TIM3->CCER = 0x3300; TIM3->SMCR = 0x0000; TIM3->DIER = 0x0000; TIM3->CR1 = 0x0001;
// Включаем прерывания
NVIC_EnableIRQ(TIM3_IRQn);
TIM3->DIER = (TIM3->DIER & ~TIM_DIER_CC1IE) | TIM_DIER_CC3IE;

Да, я люблю прямое обращение к регистрам, но это не принципиально. Это инит таймера. Сам обработчик оформляю в main.c так:

// Прерывание таймера TIM3
void TIM3_IRQHandler ( void )
{
TIM3_IRQ();
}

А в стартовом коде не забываем выставить приоритеты нужным нам прерываниям:

static void NVIC_Configuration ( void )
{
NVIC_InitTypeDef NVIC_InitStructure;

/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );

NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty = 1;
NVIC_Init( &NVIC_InitStructure );
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
}


Резюмирую: Чудес не бывает. STM32 сложнее АТмеги и там надо все делать руками. Т.е., для активации всей цепочки прерываний надо обязательно включить [тактирование] всего оборудования, что ты используешь (без исключений). Надо выставить все необходимые флаги и маски в настройках самого устройства (источники прерываний). Надо активировать необходимые прерывания в контроллере прерываний NVIC, при использовании всяких RTOS - дополнительно распределить приоритеты. Перехватить сам вектор прерывания (по умолчанию все неиспользованные вектора стоят как .weak и для перехвата просто достаточно объявить их в main.c). Если используются ноги - то и там следует настроить AF. Как-то так...

san010101
29.09.2017, 09:27
Я всю конфу делаю через STM32Cube

HardWareMan
29.09.2017, 10:13
И это печально. (с) Кубик полезен только при планировании ножек и расчета коэффициентов дерева тактирования. В остальном он бесполезен, ибо генерирует тонну говна.

san010101
29.09.2017, 10:23
Насчет лишнего я не настолько профи в STM32, мне кажется очень удобная программа.

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

Буду пробовать пока без RTOS.

HardWareMan
29.09.2017, 15:22
san010101, ну есть же тэг CODE, блин...

san010101
29.09.2017, 15:41
void TIM6_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */
static unsigned char byte=0;//выдаваемый байт
static unsigned char index=0;//номер выдаваемого бита
static unsigned short addr=0;//текущий адрес
/* USER CODE END TIM6_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */
/************************************************** ****************************/
switch (TapeOutMode)
{
/***********************пилот для заголовка******************************** ****/
case TAPE_OUT_LEAD_H:
{
if (tim6_countersec < 8063)//5 secund
{
if (tim6_counter == 21)//807Hz
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//обнуляем счетчик
tim6_countersec++;//счетчик секунд (5)
}
tim6_counter++;//счетчик 807Hz
//return;
break;
}
else
{
TapeOutMode=TAPE_OUT_SYNCHRO_1;//переход на синхро 1
TapeOutModeStart=TAPE_OUT_START_H;//флаг выбор старта пилота заголовка
tim6_counter = 0;//обнуляем счетчик
tim6_countersec = 0;//обнуляем счетчик

//gui_draw();
//return;
break;
}
}
break;
/***********************пилот для данных************************************** */
case TAPE_OUT_LEAD_D:
{
if (tim6_countersec < 3223)//2 secund
{
if (tim6_counter == 21)//807Hz
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//обнуляем счетчик
tim6_countersec++;//счетчик секунд (2)
}
tim6_counter++;//счетчик 807Hz
//return;
break;
}
else
{
TapeOutMode=TAPE_OUT_SYNCHRO_1;//переход на синхро 1
TapeOutModeStart=TAPE_OUT_START_D;//флаг выбор старта пилота данных
tim6_counter = 0;//обнуляем счетчик
tim6_countersec = 0;//обнуляем счетчик
//return;
break;
}
}
break;
/***********************синхро 1***********************************************/
case TAPE_OUT_SYNCHRO_1:
{
if (tim6_counter == 6)// ~ 171,4 мксек
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//обнуляем счетчик
TapeOutMode=TAPE_OUT_SYNCHRO_2;//переход на синхро 2
//return;
break;
}
tim6_counter++;//счетчик ~ 171,4 мксек
//return;
break;
}
break;
/***********************синхро 2***********************************************/
case TAPE_OUT_SYNCHRO_2:
{
if (tim6_counter == 7)// 200 мксек
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//обнуляем счетчик
//TapeOutMode=TAPE_OUT_DATA;
//TapeOutMode=TAPE_OUT_HEAD;
//index=0;
//byte=0;
//addr=0;
if (TapeOutModeStart==TAPE_OUT_START_H)//условия старта при пилоте заголовка
{
TapeOutMode=TAPE_OUT_HEAD;//режим вывода данных заголовка (0x1A байт )
index=0;//первоначальное значение бита
byte =0;//первоначальное значение байта
addr =0;//первоначальное значение первого байта в буфере
}
else if (TapeOutModeStart==TAPE_OUT_START_D)//условия старта при пилоте данных
{
TapeOutMode=TAPE_OUT_DATA;
index=0;//первоначальное значение бита
byte =0;//первоначальное значение байта
addr=0x1+0x17;//первоначальное значение байта в буфере после чтения заголовка
}
//return;
break;
}
tim6_counter++;//счетчик ~ 200 мксек
//return;
break;
}
break;
/***********************вывод данных HEAD**************************************/
case TAPE_OUT_HEAD:
{
//if (index>7)//проверка на чтение бит
// {
if (addr>=0x17)//проверка на чтение байт из буфера(для заголовка 0x17)
{
TapeOutMode=TAPE_OUT_LEAD_D;//выбран режим пилот для данных
byte_counter++;
//addr=0;
//gui_draw();
//return;
break;
}
//index=0;//обнуляем счетчик бит
byte=read_byte(addr);//читаем байт из буфера
//byte=read_byte(0x01);//читаем байт из буфера
addr++;//счетчик текущего обрабатываемого байта в буфере
byte_counter++;
// }
TapeOutMode=TAPE_OUT_BIT;//вывод битов в порт
}
break;
/***********************вывод данных DATA**************************************/
case TAPE_OUT_DATA:
{
//if (index>7)//проверка на чтение бит
// {
if (addr>=btr)//проверка на чтение байт из буфера
{
TapeOutMode=TAPE_OUT_STOP;//стоп передача, для чтения следующего буфера с SD-CARD
//byte_counter++;
//return;
break;
}
//index=0;//обнуляем счетчик бит
byte=read_byte(addr);//читаем байт из буфера
//byte=read_byte(0x01);//читаем байт из буфера
addr++;//счетчик текущего обрабатываемого байта в буфере
byte_counter++;
// }
TapeOutMode=TAPE_OUT_BIT;//вывод битов в порт
}
break;
/***********************вывод бит******************************************** **/
case TAPE_OUT_BIT:
{
if (byte&128) //проверка но ноль или еденицу старшего бита
{
if (tim6_counter == 17*2)//проверка условя 1023Hz единица
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//сброс счетчика 1023Hz единица
TapeOutMode=TAPE_OUT_NEXT_BIT;//выбор режима чтения следующего бита в байте
}
tim6_counter++;//счет 1023Hz единица
//return;
break;
}
else
{
if (tim6_counter == 8*2)//проверка условия 2047Hz ноль
{
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
tim6_counter = 0;//сброс счетчика 2047Hz ноль
TapeOutMode=TAPE_OUT_NEXT_BIT;//выбор режима чтения следующего бита в байте
}
tim6_counter++;//счет 2047Hz ноль
//return;
break;
}
}
break;
/***********************выбираем следующий бит для передачи********************/
case TAPE_OUT_NEXT_BIT:
{
if (index<=7)//проверка на обработку всех бит
{
byte<<=1;//сдвиг влево на 1 бит
index++;//следующий бит
}
else
{
//TapeOutMode=TAPE_OUT_STOP;//стоп передача, для чтения следующего буфера с SD-CARD
index=0;//первоначальное значение бита
//return;
}

switch (TapeOutModeStart)//выбор режима передачи байтов
{
case TAPE_OUT_START_D://если стартови данные
{
TapeOutMode=TAPE_OUT_DATA;//режим вывода данных
//index++;//следующий бит
//return;
}
break;
case TAPE_OUT_START_H://если стартовал заголовок
{
TapeOutMode=TAPE_OUT_HEAD;//режим вывода заголовка
//index++;//следующий бит
//return;
}
break;
}
}
break;
/***********************завершаем передачу и устанавливаем стартовые параметры*/
case TAPE_OUT_STOP:
{
index=0;//первоначальное значение бита
byte =0;//первоначальное значение байта
addr =0;//первоначальное значение первого байта в буфере
}
break;
/************************************************** ****************************/
case TAPE_OUT_SELECT_D:
{
if (tap_file.LenHeader==0x13||tap_file.flagHeader==0)
{
}
if (tap_file.LenHeader!=0x13||tap_file.flagHeader==0x FF)
{
}
}
break;
/************************************************** ****************************/
}
/************************************************** ****************************/
/* USER CODE END TIM6_DAC_IRQn 1 */
}

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

исправил

san010101
06.10.2017, 18:30
https://youtu.be/aHQC0d9dKhA

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

Доработки на текущий момент.
Сделан тест модулей системы.
Читает tap по байтам с карты (для отладки программы).
Перед блоками выдает пилот.
На экране отображает имя блока и порядковый номер.

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

san010101
13.10.2017, 17:16
https://cdn1.savepice.ru/uploads/2017/10/13/e4786e1b2aa46a25bbf5cca63f25f801-full.jpg (https://worldpng.ru/)

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

Все сигналы генерируются в норме.
Загрузка не удается из за отсутствия генерации последнего бита.
Разбираюсь с кодом

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



case TAPE_OUT_DATA:
{
if (index16 >=16){
if (BytesCount>=sz)//проверка на чтение байт из буфера
{
TapeOutMode=TAPE_OUT_PAUSE;//ставим паузу по оканчанию процесса
sz=FioNextHead();//читаем размер блока
BytesCount = 0;
break;
}
byte=FioNextByte();//читаем байт из буфера
index16=0;//первоначальное значение бита
BytesCount++;//общий счетчик байт файла
}

if (byte&128) //проверка на ноль или еденицу старшего бита
{
TIM6->PSC = 10265;
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
}
else
{
TIM6->PSC = 5132;
HAL_GPIO_TogglePin (GPIOD, LD6_Pin);
}
if ((index16%2)==1) byte<<=1;
index16++;
}break;

san010101
14.10.2017, 19:31
Была ещё платка stm32. Собрал на макетке. https://uploads.tapatalk-cdn.com/20171014/2a9fdfe9ddef446ce6e3eb87e1dd6b38.jpg

Отправлено с моего A0001 через Tapatalk

san010101
16.10.2017, 16:27
https://youtu.be/U96scn5DNL0

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

Вот что вышло. Ошибка при окончании загрузки.
Синхра как должна быть с ноля в еденицу ?

HardWareMan
16.10.2017, 19:28
Пилоттон, потом 1 нолик для синхры а потом данные. В конце после вывода последнего полупериода оставлять уровень без изменений.

PS Было бы круто добавить детонацию от ролика, чтобы оно так тепло и лампово раккорд тянуло ууу-ооо--уууу-оооо... :) Я помню, это не сильно влияло на качество загрузки.

san010101
17.10.2017, 06:56
Это пьезопищалка так старается.....

Проверил и с единицей в ноль и с нулем в единицу все равно в конце ошибку сыпит. Могу код скинуть.
Вот скрины анализатора.
это конец файла при синхре с нуля в еденицу
http://img.radiokot.ru/files/104486/thumbnail/1elvfnbh1u.jpg (http://img.radiokot.ru/files/104486/medium/1elvfnbh1u.jpg)
синхро
http://img.radiokot.ru/files/104486/thumbnail/1elvl6l2x4.jpg (http://img.radiokot.ru/files/104486/medium/1elvl6l2x4.jpg)



это при синхре единица в ноль
http://img.radiokot.ru/files/104486/thumbnail/1elvfnbuyc.jpg (http://img.radiokot.ru/files/104486/medium/1elvfnbuyc.jpg)
синхро
http://img.radiokot.ru/files/104486/thumbnail/1elvn19vy2.jpg (http://img.radiokot.ru/files/104486/medium/1elvn19vy2.jpg)

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

ps
У меня STM32 логика 3.3 В
Подключаю напрямую с выхода контроллера ко входу zx spectrum
В спектруме загрузщик не распаян(арлекин 48)
я подключил напрямую ко входу микросхемы.
Может нужна какая развязка?

san010101
17.10.2017, 10:43
https://youtu.be/9JVQ2NzWmuw
Загрузка Диззи
Запускается с музыкой и виснет в игре

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

Вообще файлы грузятся по разному, одни через пару блоков R tape error выдают другие могут загрузится и зависнуть

goodboy
17.10.2017, 11:19
в некоторых загрузчиках нет проверки на ошибку, поэтому софт может быть частично работоспособный.
а у тебя похоже сбой на длинных блоках.
проще проверить грузя данные в какой-нибудь копировщик
(он хоть покажет ошибку контрольной суммы)
как вариант можно сделать verify code (например с ПЗУ)

Spectramine
17.10.2017, 14:21
https://youtu.be/U96scn5DNL0

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

Вот что вышло. Ошибка при окончании загрузки.
Синхра как должна быть с ноля в еденицу ?

Синхра это два полупериода заданной длины - 667 тактов/735 тактов. Для стандартного загрузчика полярность не важна.

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

А другие прерывания, кроме от таймера, не могут произойти?

san010101
17.10.2017, 15:25
Вот и думаю как проверить. Пока нужно отработать алгоритм. У меня каждый байт с карты читается. Без буферизации. Возможно в этом причина. Тестирую сейчас копировщиком для ленты.

san010101
17.10.2017, 18:54
http://img.radiokot.ru/files/104486/thumbnail/1emi0d9xp4.jpg (http://img.radiokot.ru/files/104486/medium/1emi0d9xp4.jpg)
отловил глюк анализатором

HardWareMan
17.10.2017, 21:41
А ты как формируешь то периоды? По CAPT или просто настраиваешь таймер на следующее событие?

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

А, вижу код страницей ранее. Думаю, у тебя достаточно сложное дерево алгоритма в обработчике прерываний. Я бы каждый блок "рендерил" в битстрим в ОЗУ а по таймеру протягивал его на порт (собственно, я так и делаю в программе на РС). Но и это не главное. Главное, что ты упустил вот это:

void xIRQ()
{
uint16_t Events;
***
// Сохраним список евентов и подтвердим обработку
Events = TIM3->SR; TIM3->SR = 0x0000;
// Это евент каптуры CAPT3
if (Events & TIM_SR_CC3IF)
***
// Это евент каптуры CAPT1
if (Events & TIM_SR_CC1IF)
***

И так далее. У тебя может стрелять другое событие. Следует разделять события, ведь на них всех всего один общий обработчик.

san010101
18.10.2017, 04:41
Это обработчик прерывания таймера 6



void TIM6_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */
/* USER CODE END TIM6_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */

if (TapeOutMode==TAPE_OUT_STOP)
{
HAL_GPIO_WritePin(GPIOD, LD6_Pin, GPIO_PIN_RESET);
return;
}
if (TapeOutVolume==true)
{
HAL_GPIO_WritePin(GPIOD, LD6_Pin, GPIO_PIN_RESET);
TapeOutVolume=false;
}
else
{
HAL_GPIO_WritePin(GPIOD, LD6_Pin, GPIO_PIN_SET);
TapeOutVolume=true;
}

//выводим пилот-тон
if (TapeOutMode==TAPE_OUT_LEAD)
{
TIM6->PSC = 13011;//начальное значение таймера
if (tim6_countersec > 0) tim6_countersec--;
else
{
tim6_countersec = 3223;
TapeOutMode=TAPE_OUT_SYNCHRO_1;
return;
}
}

//выводим синхросигнал 1
if (TapeOutMode==TAPE_OUT_SYNCHRO_1)
{
TIM6->PSC =4050;//начальное значение таймера
TapeOutMode=TAPE_OUT_SYNCHRO_2;
return;
}

//выводим синхросигнал 2
if (TapeOutMode==TAPE_OUT_SYNCHRO_2)
{
TIM6->PSC = 4420;//начальное значение таймера
TapeOutMode=TAPE_OUT_DATA;
index16=16;
byte=0;
BytesCount=0;//обнуляем счетчик байт
return;
}

//передаём данные
if (TapeOutMode==TAPE_OUT_DATA)
{
if (index16>=16)
{
if (BytesCount>=sz)
{
TapeOutMode=TAPE_OUT_STOP;
BytesCount = 0;
return;
}
byte=FioNextByte();//читаем байт из буфера
byte_temp = byte;
index16=0;//первоначальное значение бита
BytesCount++;//общий счетчик байт файла
}
//выдаём бит
if (byte&128) {
TIM6->PSC = 10265;//начальное значение таймера
}
else {
TIM6->PSC = 5132;//начальное значение таймера
}
if ((index16%2)==1) byte<<=1;
index16++;
return;
}

}

HardWareMan
18.10.2017, 07:28
TIMx->PSC это прескалер. Почему оно подписано как "начальное значение" если сам таймер это TIMx->CNT?

san010101
18.10.2017, 08:07
Сам таймер 6 у меня настроен на 42 000 000 Гц
42 000 000 / 13011 = 3228,0378141572515563753746829606
3228,0378141572515563753746829606 / 4 = 807,00945353931288909384367074014
получаем частоту пилот тона

HardWareMan
18.10.2017, 12:47
Хорошо. Какое событие ты используешь и чему равен ARR регистр? Да и хотелось бы выяснить режим таймера в целом.

san010101
18.10.2017, 14:02
CubeMX Настройки таймера

http://img.radiokot.ru/files/104486/thumbnail/1endgxt22c.jpg (http://img.radiokot.ru/files/104486/medium/1endgxt22c.jpg)

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

http://img.radiokot.ru/files/104486/thumbnail/1endioe48o.jpg (http://img.radiokot.ru/files/104486/medium/1endioe48o.jpg)

Все прерывания
http://img.radiokot.ru/files/104486/thumbnail/1endmv1aci.jpg (http://img.radiokot.ru/files/104486/medium/1endmv1aci.jpg)

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


/* TIM6 init function */
void MX_TIM6_Init(void)
{

TIM_MasterConfigTypeDef sMasterConfig;

htim6.Instance = TIM6;
htim6.Init.Prescaler = 120;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 1;
HAL_TIM_Base_Init(&htim6);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig);
}

san010101
20.11.2017, 18:19
На днях провел тестирование своей поделки, успешно заработала!
Загрузка tap файлов работает.

Пока тестирую на эмуляторе Spectaculator
загрузка через линейный вход звуковой карты.


https://youtu.be/Qi37Imy5Sy0

HardWareMan
20.11.2017, 20:14
Плохо смотреть вертикальное видео.

san010101
21.11.2017, 12:30
Видео заменил

san010101
22.11.2017, 14:17
Кто подключал внешнюю статическую память к STM32?

HardWareMan
22.11.2017, 14:44
Через FSMC?

san010101
22.11.2017, 18:34
Уже читаю статьи. Какая память подойдёт?


Отправлено с моего A0001 через Tapatalk

HardWareMan
22.11.2017, 21:14
Можно любую: SDRAM, SRAM (конкретную поддержку смотреть в референс мануале на семейство). Можно еще и NAND повесить за одно. Весь сок FMSC в том, что память (NOR или RAM) отражается в адресном пространстве и может быть использовано для исполнения кода и ПДП.

san010101
25.11.2017, 09:38
https://youtu.be/lbvZqNBj6CM
Работы над интерфейсом пользователя.

san010101
26.11.2017, 19:43
Как реализовать запись сигнала?

Отправлено с моего A0001 через Tapatalk

HardWareMan
27.11.2017, 07:05
Уже же сделано. Реализуй как битстрим, чтобы не привязываться к форматам. Т.е., сигнал бинарный (0 или 1), в байте 8 сэмплов. Сэмплрейт - не знаю, можно поиграть с разным. Но думаю выше 10кГц ставить смысла нет. А при 10кГц трата будет примерно 10 000 / 8 = 1250 байт/с, что вполне укладывается в скорость записи на SD даже через SPI (а ты же ее подключил через SDIO, ведь так?). 5 минут файл будет примерно 360кБайт.

san010101
29.11.2017, 19:09
Сделал функцию паузы, стоп, перемотка блоков файла вперёд и назад.
Теперь буду тестировать и отлаживать код.

Отправлено с моего A0001 через Tapatalk

san010101
30.11.2017, 14:47
Для zx если делать, у него на выходе тоже частотно импульсная модуляция?

Отправлено с моего A0001 через Tapatalk

HardWareMan
02.12.2017, 16:16
san010101, какого именно таймера? RTOS захватывает только системный.

san010101
02.12.2017, 19:08
Я про запись программ со спектрума.
ZX на выход цифровой сигнал выдаёт а потом в схеме он преобразует в частотно модулированый сигнал. То есть мне либо цифру снимать и потом её в tap файл кодировать либо для полной совместимости с оригиналом частотно импульсный сигнал снимать.


Отправлено с моего A0001 через Tapatalk

HardWareMan
02.12.2017, 20:01
Там же двухуровневый сигнал. Какая проблема его "оцифровывать" и паковать 8 сэмплов в байт?

san010101
06.12.2017, 18:05
Можно подробнее рассказать про запись или ссылку где почитать?

Отправлено с моего A0001 через Tapatalk

goodboy
06.12.2017, 18:58
Можно подробнее рассказать про запись или ссылку где почитать?
http://vtrd.in/book/REVU9145.ZIP
статья - "секреты ПЗУ"
вникать в SA_BYTES

san010101
07.12.2017, 10:04
Уже же сделано. Реализуй как битстрим, чтобы не привязываться к форматам. Т.е., сигнал бинарный (0 или 1), в байте 8 сэмплов. Сэмплрейт - не знаю, можно поиграть с разным. Но думаю выше 10кГц ставить смысла нет. А при 10кГц трата будет примерно 10 000 / 8 = 1250 байт/с, что вполне укладывается в скорость записи на SD даже через SPI (а ты же ее подключил через SDIO, ведь так?). 5 минут файл будет примерно 360кБайт.

Можно подробней раскрыть тему и желательно где почитать с примерами.

HardWareMan
07.12.2017, 10:11
san010101, я точно не помню, но вроде все было описано вот в этой теме (http://zx-pk.ru/threads/25622-magnitofon-dlya-spektruma-na-atmega128.html). Сам файл имеет расширение BAW - Binary wAVe.

san010101
07.12.2017, 10:37
Пока вижу это как использовать таймер в режиме захвата для отсчета единиц и нулей. Хорошо бы примеры работы для stm32

san010101
12.12.2017, 10:19
void EXTI15_10_IRQHandler(void)
{
/* USER CODE BEGIN EXTI15_10_IRQn 0 */

/* USER CODE END EXTI15_10_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);

/* USER CODE BEGIN EXTI15_10_IRQn 1 */
/*********************блок переменных****************************** ******************************/
static const uint8_t delta = 50; //дельта для диапозона пилот тона
static const uint16_t pilot_ARR = 2168*2; //значение таймера для пилот-тона 807Гц
static const uint16_t syn1_ARR = 667; //значение таймера synchro1 5247Гц
static const uint16_t syn2_ARR = 735; //значение таймера synchro2 4761Гц
/************************************************** *********************************************/

/********************чтение пилот-тона****************************************** ****************/
if (TapeInMode==TAPE_IN_LEAD){
TIM6->ARR = pilot_ARR;
//EXTI->FTSR |= 0x15; //по спадающему фронту

if (TapeIn==true){
TIM6->CNT = 0; //начальное значение для отсчета
HAL_TIM_Base_Start (&htim6);
HAL_TIM_Base_Start_IT (&htim6); //включить таймер
TapeIn=false; //переключатель на выкл. таймера
EXTI->PR |= (0x15); //Очищаем флаг и останавливаем прерывание
return;
}
else{
HAL_TIM_Base_Stop (&htim6);
HAL_TIM_Base_Stop_IT (&htim6); //выключить таймер
counterbit = __HAL_TIM_GET_COUNTER(&htim6); //взять значение отсчета таймера

/*проверка на ввод пилот тона, если нет сигнала то стоп прием и переход к ледующему шагу*/
if ((counterbit > pilot_ARR-delta) && (counterbit < pilot_ARR+delta) ) {
#if Debug_TIM
SEGGER_RTT_printf(0,"\n counterbit %u\n", counterbit);
#endif
TapeInMode = TAPE_IN_LEAD; //продолжим прием пилот-тона
TapeIn=true; //переключатель на старт таймера
}
else
{
#if Debug_TIM
SEGGER_RTT_printf(0,"\n Exit %u\n", counterbit);
#endif

TIM6->ARR = syn1_ARR;
EXTI->RTSR |= 0x15; //по нарастающему фронту
EXTI->PR |= (0x15); //Очищаем флаг и останавливаем прерывание
TIM6->CNT = 0; //начальное значение для отсчета
HAL_TIM_Base_Start (&htim6);
HAL_TIM_Base_Start_IT (&htim6); //включить таймер

TapeInMode = TAPE_IN_SYNCHRO_1; //прием Synchro1

}
return;
}
}

/********************читаем синхросигнал 1************************************************* *****/
if (TapeInMode==TAPE_IN_SYNCHRO_1){

HAL_TIM_Base_Stop (&htim6);
HAL_TIM_Base_Stop_IT (&htim6); //выключить таймер
counterbit = __HAL_TIM_GET_COUNTER(&htim6); //взять значение отсчета таймера
EXTI->PR |= (0x15); //Очищаем флаг и останавливаем прерывание
EXTI->FTSR |= 0x15; //по спадающему фронту
TIM6->ARR = syn2_ARR;

#if Debug_TIM
SEGGER_RTT_printf(0,"\n Exit Synchro1 %u\n", counterbit);
#endif


TIM6->CNT = 0; //начальное значение для отсчета
HAL_TIM_Base_Start (&htim6);
HAL_TIM_Base_Start_IT (&htim6); //включить таймер

TapeInMode = TAPE_IN_SYNCHRO_2; //стоп прием
return;}

/************************************************** ************************************************/

/********************читаем синхросигнал 2************************************************* *****/
if (TapeInMode==TAPE_IN_SYNCHRO_2){

HAL_TIM_Base_Stop (&htim6);
HAL_TIM_Base_Stop_IT (&htim6); //выключить таймер
counterbit = __HAL_TIM_GET_COUNTER(&htim6); //взять значение отсчета таймера
TapeInMode = TAPE_IN_STOP; //стоп прием
EXTI->PR |= (0x15); //Очищаем флаг и останавливаем прерывание
EXTI->RTSR |= 0x15; //по нарастающему фронту

#if Debug_TIM
SEGGER_RTT_printf(0,"\n Exit Synchro2 %u\n", counterbit);
#endif

TapeIn=true; //переключатель на старт таймера
return;}

/************************************************** ************************************************/
/* USER CODE END EXTI15_10_IRQn 1 */
}


Вход 807Гц держит, определяет.
Теперь нужно синхроимпульсы отработать.
Первый по высокому фронту, а второй по низкому.
Пока не получилось, может, что пропустил ?

san010101
06.09.2018, 18:58
Всем привет. После продолжительного перерыва вернулся к проекту. Теперь работаю с цветным экраном 320х240
Пока поддержка только tap в режиме чтения. Есть возможность просматривать файлы jpeg, txt и zx spectrum образ экрана scr.
Именно этот файл грузится при загрузке tap в качестве экранки. Добавлен прогресс бар.

Отправлено с моего A0001 через Tapatalk
https://youtu.be/Tvg1SUaCBxs

tank-uk
07.09.2018, 22:17
san010101, ёёё моё, я уважаю ваш труд и стремление, но не проще купить за те же $20 какую то какашку на андроид и не париться ? в плеймаркете дофига прог для проигрывания TAP и TZX и все они работают, да еще и реально работают WAV с супер-турбо загрузкой

не хотел ни кого обидеть, это так, мысли в слух

san010101
08.09.2018, 09:49
По большому счету тут все можно перевести в алиэкспер или плай маркет. Компы на ПЛИС или эмулятор, различныу переферию на али экспресс или программно.

san010101
27.11.2018, 16:26
https://youtu.be/3cCmEcKgLh0

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

Немного по развлекался с esp32. Пока только просмотр списка файлов и вывод файлов экрана zx spectrum

san010101
10.07.2020, 13:16
https://youtu.be/9AbXD-k8myw
Добрался до давнего проекта, провел эксперименты с режимом таймера захват. Удалось считать тестовые данные и собрать их в принимаемые байты. Далее запись на карту и на выходе имеет zx tap файл. То есть устройство будет записывать информацию с ZX-Spectrum как магнитофон и кодировать сразу в tap файл.

Viktor2004
18.05.2021, 20:51
Здравствуйте.
Еще работаете над проектом? Новости есть?

Зайцев
16.06.2022, 07:22
Проект живой?