STM32F103-Synthesizer с аналоговыми фильтрами

Мадиас
Вторник 01 сентября 2015 г. 22:00
Хорошо, время для публикации моих идей для моего основного проекта здесь.
Вначале только несколько быстрых фактов и обновлений статуса:

Концепция:
4-канальный (полифонический) Waveetable-Synthesizer на основе STM32F103 с отдельными выходами для платы аналоговых фильтров.
Голосовать через 2pcs pt8211 (дешевый) Audio DAC [Основной код работает - пока невозможно, но благодаря Vassilis с SPI -кодом, TODO: реализация DMA]
USB-MIDI и аппаратный MIDI [Настроили отдельную филиал с использованием USB-MIDI вместо USB-серии-тестовый код работал]
Дисплей (ILI9341 с прикосновением + вторичный OLED), кодеры, ручки.... [Тодо, но сначала нет приоритета для пользовательского интерфейса]
Прямой импорт Waldorf Blofeld Multi-Wavetables через MIDI (USB) [Работайте, код написан]
SPI-Flash (Winbond) EEPROM (2-4 МБ) для хранения maybe an additional I2C EEPROM (more write/erase cycles) several LTC1665 octal-8-Bit-DAC's for controlling the filter board and voice volume [code examples written, maybe I use direct PWM instead of this DAC's] STM32F103 is individual, but I need 64k RAM (for wavetables), so maybe RET6 [b]Filter board[/b] [i]based on Olivier Gillet Anushri 4-Pole filter board[/i] Stackable 4-pole LP Filter board (each board with 2x Filter + PT8211 DAC - routable) [created with Kicad uploaded to production: dirtypcbs.com] Used chips: Mostly SSM2164 (aka V2164) and LM13700, rest TL07x, Styroflex caps for filter) 3d-model: [img]http://666kb.com/i/d1qbw6ccyw991xrfv.jpg[/img] [i][b]to be continued[/b][/i]

victor_pv
Ср. 02 сентября 2015 г., 4:16
Мадиас написал:Хорошо, время для публикации моих идей для моего основного проекта здесь.
Вначале только несколько быстрых фактов и обновлений статуса:

Концепция:
4-канальный (полифонический) Waveetable-Synthesizer на основе STM32F103 с отдельными выходами для платы аналоговых фильтров.
Голосовать через 2pcs pt8211 (дешевый) Audio DAC [Основной код работает - пока невозможно, но благодаря Vassilis с SPI -кодом, TODO: реализация DMA]
USB-MIDI и аппаратный MIDI [Настроили отдельную филиал с использованием USB-MIDI вместо USB-серии-тестовый код работал]
Дисплей (ILI9341 с прикосновением + вторичный OLED), кодеры, ручки.... [Тодо, но сначала нет приоритета для пользовательского интерфейса]
Прямой импорт Waldorf Blofeld Multi-Wavetables через MIDI (USB) [Работайте, код написан]
SPI (Winbond) EEPROM (2-4 МБ) для хранения maybe an additional I2C DAC (more write/erase cycles) several LTC1665 octal-8-Bit-DAC's for controlling the filter board and voice volume [code examples written, maybe I use direct PWM instead of this DAC's] STM32F103 is individual, but I need 64k RAM (for wavetables), so maybe RET6 [b]Filter board[/b] [i]based on Olivier Gillet Anushri 4-Pole filter board[/i] Stackable 4-pole LP Filter board (each board with 2x Filter + PT8211 DAC - routable) [created with Kicad uploaded to production: dirtypcbs.com] Used chips: Mostly SSM2164 (aka V2164) and LM13700, rest TL07x, Styroflex caps for filter) 3d-model: [img]http://666kb.com/i/d1qbw6ccyw991xrfv.jpg[/img] [i][b]to be continued[/b][/i][/quote] May I suggest you use SPI Flash instead of EEPROM? perhaps you meant that, but if not, flash should be faster than eeprom. Regarding the MCU, the RCT6 boards I have all have 512 of flash and 64 of RAM, so at least for development you can use that. Both the RCT and RET have 2 integrated DACs, so you can use those for control, or extra channel or whatever you wish.

Мадиас
Ср. 02 сентября 2015 г. 5:43 утра
Дорогой Виктор,
Да, я имею в виду SPI Flash (например, Winbond W25Q64FV). Реальная проблема - циклы записи/чтения, взятые из таблиц данных:
W25Q64FV - 8MB Flash SPI чип (100.000 циклов записи)
24LC512 - 64 КБ Flash I2C Чип (1.000.000 циклов записи)
Таким образом, для «хранения данных постоянного в лету» (данные, подобные патчам, общие файлы, без аудиофайлов), 23LC512 должен быть лучшим вариантом. Но, может быть, я слишком осторожный. Аудио играется напрямую из внутренней оперативной памяти, поэтому мне не понадобится настоящая высокая скорость для внешнего хранилища.
Для разработки я использую мою большую ветеринарную доску (Winbond и I2C Flash на борту) для конечного продукта, который я еще не уверен.
DAC может быть полезен (если нет конфликта с PIN -конфликтом с SPI, мне нужны все 3 порта SPI), но только два ПК проблематичны, потому что мне нужно следовать теме (!) ЦАП (или отфильтрованные ШИМ):
4x контролируемый объем напряжения (VCA)
4x контролируемая частота отсечения напряжения (VCF)
1-4x контролируемого напряжения резонанс (---> Может быть, это для ЦАП, мне не нужно устанавливать резонанс для каждого независимого от голоса)
Итак, один октальный DAC + 1Channel On Board DAC.

victor_pv
Ср. 02 сентября 2015 г. 13:14
Мадиас написал:Дорогой Виктор,
Да, я имею в виду SPI Flash (например, Winbond W25Q64FV). Реальная проблема - циклы записи/чтения, взятые из таблиц данных:
W25Q64FV - 8MB Flash SPI чип (100.000 циклов записи)
24LC512 - 64 КБ Flash I2C Чип (1.000.000 циклов записи)
Таким образом, для «хранения данных постоянного в лету» (данные, подобные патчам, общие файлы, без аудиофайлов), 23LC512 должен быть лучшим вариантом. Но, может быть, я слишком осторожный. Аудио играется напрямую из внутренней оперативной памяти, поэтому мне не понадобится настоящая высокая скорость для внешнего хранилища.
Для разработки я использую мою большую ветеринарную доску (Winbond и I2C Flash на борту) для конечного продукта, который я еще не уверен.
DAC может быть полезен (если нет конфликта с PIN -конфликтом с SPI, мне нужны все 3 порта SPI), но только два ПК проблематичны, потому что мне нужно следовать теме (!) ЦАП (или отфильтрованные ШИМ):
4x контролируемый объем напряжения (VCA)
4x контролируемая частота отсечения напряжения (VCF)
1-4x контролируемого напряжения резонанс (---> Может быть, это для ЦАП, мне не нужно устанавливать резонанс для каждого независимого от голоса)
Итак, один октальный DAC + 1Channel On Board DAC.

Мадиас
Ср. 02 сентября 2015 г., 13:29
Есть также устройства SPI RAM, Я знаю их, у меня есть как минимум два из них из доставки образца микрочипа дома. (У меня есть много чипсов SPI/I2C Flash/EEPROM/RAM, поэтому я собираюсь поэкспериментировать лучше всего) И у RC и выше есть FSMC Я думал о FSMC и добавлении около 1-2 МБ SRAM (NORS), но фактически они мне не нужны (64 КБ более чем достаточно для меня и для волн), возможно, это может быть будущим обновлением: «Реальные» образцы вместо Wavetables. О ЦАП, возможно, есть несколько восьмиугольников или, по крайней мере, Quad DAC, которые работают со SPI, в режиме SPI не i2s У меня есть 8-битный восьми цифровую ЦАП LT1665 -> это SPI, но быть бетоном:
Мне нужно 4-битный DAC для Audio Out, поэтому 2PCS Pt8211 идеально подходит для этого условия ---> Частота 48 кГц. Волноты в реальном времени творены с этой частотой Я знаю, что работа i2s будет отличной выгодой.
Остальные ЦАП предназначены для контрольных линий, им не нужна высокая частота (обновление около 40-100 Гц, и только в случае изменения значения) и без более высокой скорости битов (8-битный больше, чем хорошо, потому что я использую конвертеры выставки. В моей схеме аудиофильтрования MIDI «Понять» только 7-битные значения для нормальных сигналов CC (и одна линия с 14-битной -> изгиб тона), поэтому 8-битный))) Я также реализовал в дизайне фильтра A PWM-фильтр, поэтому я также попробую PURE SWM (с более высокой скоростью), но мне понадобится не менее 9 пин-штифтов.

Итак, мои следующие шаги, пока я не получу платы PCB:
Оптимизация кода Audio Out с помощью ЦАП PT8211 (даже с DMA SPI или I2s (но, честно говоря: я не вижу, чтобы I2 работали с моими навыками)

victor_pv
Чт 10 сентября 2015 12:44
Я ничего не знаю о LFO, но звучит как работа для торговых таймеров аппаратного обеспечения. Им просто нужно переключить булавку на определенной частоте, и эта частота может меняться время от времени, это правильно?
Если это так, вы можете использовать 1 или несколько таймеров, с правильными значениями для перезагрузки, прескалера и OCR, и установить их на свободный запуск, затем измените значения на лету, чтобы изменить их частоту и период.
Я полагаю, что у вас будет 7 таймеров, доступных в RCT или более высоких MCU, каждый из которых с 4 выходами сравнивает выходы.

Мадиас
Чт 10 сентября 2015 г. 13:25
LFO - это скорее модульная вещь, от конструкции, как «нормальные» осцилляторы:
Изображение синусоидальной таблицы с 256 записями. (Значения от -127 до 127). Вы проходите через эту таблицу с переменной частотой (скажем, 30 Гц). Таким образом, вы установили таймер с частотой 7680 Гц (256*30 Гц). Это было бы довольно плохо, но функциональный LFO. (Чтобы изменить частоту, вы должны изменить таймер)
Использование этого LFO является модульным, некоторые примеры:
Вы можете модулировать шаг основного генератора: частота основного генератора составляет 440 Гц (концертный шаг «а»).
Есть много целей, которые вы можете модулировать: объем, частота отсечения, баланс между осциллятором1 и OSC2, даже интенсивность LFO2 или скорость LFO3.
Таким образом, в моем синтезаторе LFO будет только «быть в программном обеспечении», изменяя шаг OSC, но даст отдельное значение DAC, если бы я модулировал обрезанный фильтр (внешнее аналоговое оборудование)
В прошлом я делал это с одним таймером для всех LFO:
(Пример кода из моего мозга)
Эта функция находится на таймере, установленном на желаемую максимальную частоту * 256 byte div_delay[MAX_VOICES*3]; byte lfo_table_counter[MAX_VOICES*3]; byte lfo_freq[MAX_VOICES*3]; int8_t lfo_value[MAX_VOICES*3]; // lfo_table[] different tables with 256 entries (like sine, sqr, saw up....) lfo_freq[0]=20; lfo_freq[1]=100; // and so on... void LFO() { for (byte currentvoice=0;currentvoice<=MAX_VOICES*3;currentvoice++) // need 3 LFO's for each voice { div_delay[currentvoice]++; if (div_delay[currentvoice]>=freq[currentvoice]) lfo_table_counter[currentvoice]++; lfo_value[currentvoice]=lfo_table[currentvoice]; } }

Мадиас
Чт 10 сентября 2015 г. 15:39
Хорошо, попробовал RTOS в моем примере i2S, со смешанным успехом:
Корочно, усечен:
Перед настройкой: SemaphoreHandle_t event_signal;

victor_pv
Чт 10 сентября 2015 г., 20:07
Не могли бы вы ссылаться на полный эскиз?

РЕДАКТИРОВАТЬ:
Попробуйте установить время ожидания семафора как portmax_delay, а не NULL

Кроме того, почему вы принимаете семафор после его создания?
Это так, что процедура DMA сначала отправляет партию 0? в противном случае, вам не нужно принимать это, пусть задача заполнения буфера возьмет это.

Мадиас
Чт 10 сентября 2015 г. 20:28
...Между тем я сразился с другой проблемой. Если я установите буфер DMA на высокий. Никаких кликов не происходит, если я установил буфер на 2 (только 1 значение для слева/справа)
У меня снова полный аудио-двигатель в DMA, если я не смогу очистить проблемы. У меня есть 2-3 задачи RTOS: некоторые гаджеты TFT, игрок с заметками и LFO.
Это тяжелое начало изучать RTO, потому что я использую критические вещи в реальном времени.

Я добавил версию «до» моего эскиза (аудио -двигатель на RTO) только две задачи: мелодия (включенная только развертка FREQ) и Audio_Engine. (TFT - это только начальный экран), как вы можете видеть в DMA IRQ, я пробовал много неуместных кодов.

Я думаю, что лучшее было бы «функция rtos One Trigger» для Audio_Engine --> Триггер будет в DMA IRQ, потому что это немного пустая трата ресурсов, имея петлю Audio_Engine "всегда на"
Второй файл эскиза (i2S-PT8211-Synth-Buffer_tft_rtos2)-мой текущий рабочий эскиз (кроме проблемы буфера, он работает довольно хорошо)

редактировать: Кроме того, почему вы принимаете семафор после его создания? Это было только для тестирования (я видел это в примере)

Мадиас
Чт 10 сентября 2015 г. 20:49
Я думаю о чем -то подобном:
http: // www.Freertos.org/taskresumefromisr.HTML

DMA IRQ установил задачу AUDIO_ENGINE в резюме, задача запускает и прекращается.
Другая теория: время обновления задачи составляет 1 кГц, но я использую около 48 кГц в DMA IRQ (настройка более высокой скорости в RTOS-конфиг не приносит лекарство)

victor_pv
Чт 10 сентября 2015 г. 20:56
Мадиас написал:Я думаю о чем -то подобном:
http: // www.Freertos.org/taskresumefromisr.HTML

DMA IRQ установил задачу AUDIO_ENGINE в резюме, задача запускает и прекращается.
Другая теория: время обновления задачи составляет 1 кГц, но я использую около 48 кГц в DMA IRQ (настройка более высокой скорости в RTOS-конфиг не приносит лекарство)

Rogerclark
Чт 10 сентября 2015 г., 21:00
Freertos Systick вызывается той же функцией, которая обновляет количество Millis (), поэтому, если вы измените скорость Systick, вам необходимо скорректировать код Millis ()

Мадиас
Чт 10 сентября 2015 г., 21:20
Попробуйте установить время ожидания семафора как portmax_delay, а не NULL Да, это смешивает слегка белый шум с аудио -выводом, звучит очень хорошо, но не то, что я хочу :)
Хорошо, я получил его почти запуска (но с худшим качеством звука, чем все в DMA ISR), потому что я установил Audio_Engine для более низкой задачи. Смотрите добавленный набросок

Хорошо, есть возможность установить временную задачу для более высокого приоритета, но синтаксис я немного смущаю меня:
Я пытался void DMAEvent() { BaseType_t xHigherPriorityTaskWoken = pdTRUE; xSemaphoreGiveFromISR(event_signal, &xHigherPriorityTaskWoken ); // trigger portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); dma_clear_isr_bits(DMA2, DMA_CH2); }

victor_pv
Пт 11 сентября 2015 г. 12:31
Но вы все еще используете это: static void vFillBufferTask(void *pvParameters) { while (1) { if (xSemaphoreTake(event_signal, 0)) {

victor_pv
Пт 11 сентября 2015 г., 4:56 утра
Попробуйте этот код. Извините, у меня не было времени, чтобы скомпилировать его, поэтому у нее может быть небольшая ошибка, но если вы посмотрите на DMA ISR и функцию буфера заполнения, вы должны получить идею в очереди. /* Pins: #define BOARD_SPI3_NSS_PIN PA15 x timer #define BOARD_SPI3_SCK_PIN PB3 x timer #define BOARD_SPI3_MISO_PIN PB4 x timer #define BOARD_SPI3_MOSI_PIN PB5 x timer MCK Pins: I2S2MCK: PC6 Timer 8, Channel 1 I2S3MCK: PC7 Timer 8, Channel 2 #define BOARD_SPI1_NSS_PIN PA4 #define BOARD_SPI1_SCK_PIN PA5 #define BOARD_SPI1_MISO_PIN PA6 #define BOARD_SPI1_MOSI_PIN PA7 */ #include #include "libmaple/spi.h" #include "libmaple/dma.h" #include "header.h" #include #include #include #include #include #include "fonts/Arial14.h" #define TFT_DC PA1 #define TFT_CS PA0 #define rst PA2 #define BLACK 0x0000 #define RED 0xF800 #define GREEN 0x07E0 //#define BLUE 0x001F #define BLUE 0x102E #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define ORANGE 0xFD20 #define GREENYELLOW 0xAFE5 #define DARKGREEN 0x03E0 #define WHITE 0xFFFF // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, rst); ILI9341_due_gText t1(&tft); #define LED PD2 #define buffer_size 2 #define buffer_size 128 int16_t i2s_buffer[buffer_size]; int16_t * i2s_buffer_tophalf = &i2s_buffer[buffer_size/2]; int16_t * i2s_buffer_ptr; QueueHandle_t dmaQueue; SemaphoreHandle_t event_signal; xTaskHandle TaskHandle_1; byte melo[] = { 40, 52, 40, 52, 47, 59, 47, 59, 40, 52, 40, 52, 47, 59, 47, 59, 43, 55, 43, 55, 50, 62, 50, 62, 43, 55, 43, 55, 50, 69, 50, 69, }; byte wavecounter2 = 0; byte counter = 0; byte notestep = 0; byte dacval = 0; byte dacval2 = 0; volatile byte testvol = 127; volatile byte testvol2 = 127; byte freq = 30; void setup() { disableDebugPorts(); // need to use SPI3!!!! Serial.begin(9600); tft.begin(); tft.setRotation(iliRotation270); tft.fillScreen(BLUE); t1.defineArea(0, 0, 320, 240); t1.selectFont(Arial14); timer_set_mode(TIMER6, 2, TIMER_DISABLED); // disable pwm on pins fuer jeden setzen! gpio_set_mode(GPIOA, 15 , GPIO_AF_OUTPUT_PP); // SS pin gpio_set_mode(GPIOB, 3 , GPIO_AF_OUTPUT_PP); // sck gpio_set_mode(GPIOB, 4 , GPIO_INPUT_FLOATING); // miso gpio_set_mode(GPIOB, 5 , GPIO_AF_OUTPUT_PP); // mosi gpio_set_mode(GPIOC, 7 , GPIO_AF_OUTPUT_PP); // bck createNoteTable(SAMPLE_RATE); createWavetables(); ulPhaseIncrement_A[0] = nMidiPhaseIncrement[69]; // 69=440hz reference ulPhaseIncrement_A[1] = nMidiPhaseIncrement[69]; // 69=440hz reference pinMode (LED, OUTPUT); tft.fillRect(0, 0, 320, 15, RED); t1.setFontColor(WHITE, RED); t1.drawString("* ILI9341_due UTFT 240x320 Demo *", 47, 0); tft.fillRect(0, 226, 320, 240, tft.color565(64, 64, 64)); t1.setFontColor(YELLOW, tft.color565(64, 64, 64)); t1.drawString("bis dahin komm ich", gTextAlignBottomCenter, 227); i2s_begin(SPI3); // untere Funktion verwenden // ****DMA ****** dma_init(DMA2); spi_tx_dma_enable(SPI3); dma_attach_interrupt(DMA2, DMA_CH2, DMAEvent); spi_tx_dma_enable(SPI3); dma_setup_transfer(DMA2, DMA_CH2, &SPI3->regs->DR, DMA_SIZE_16BITS, i2s_buffer, DMA_SIZE_16BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_FROM_MEM | DMA_HALF_TRNS | DMA_TRNS_CMPLT)); dma_set_num_transfers(DMA2, DMA_CH2, buffer_size); dma_set_priority(DMA2, DMA_CH2, DMA_PRIORITY_VERY_HIGH); dma_enable(DMA2, DMA_CH2);// enable transmit testvol = 127; dmaQueue = xQueueCreate ( 2, sizeof (int16_t) ); vSemaphoreCreateBinary( event_signal ); // Create the semaphore xSemaphoreTake(event_signal, 0); // Take semaphore after creating it. xTaskCreate(vFillBufferTask, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &TaskHandle_1); xTaskCreate(vMusicTask, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler(); } void loop() { } static void vMusicTask(void *pvParameters) { while (1) { freq++; if (freq == 90) freq = 30; testvol = 127; ulPhaseIncrement_A[0] = nMidiPhaseIncrement[byte(freq)]; // should be 440hz ulPhaseIncrement_B[0] = nMidiPhaseIncrement[byte(freq)]; ulPhaseIncrement_A[1] = nMidiPhaseIncrement[byte(90-freq)]; // should be 440hz ulPhaseIncrement_B[1] = nMidiPhaseIncrement[byte(90-freq)]; vTaskDelay(100); /* byte tune = melo[notestep]; ulPhaseIncrement_A[0] = nMidiPhaseIncrement[byte(tune)]; ulPhaseIncrement_B[0] = nMidiPhaseIncrement[byte(tune) + 7]; ulPhaseIncrement_A[1] = nMidiPhaseIncrement[byte(tune + 12)]; ulPhaseIncrement_B[1] = nMidiPhaseIncrement[byte(tune) + 19]; // Serial.println(nMidiPhaseIncrement[byte(tune)] ); notestep += 1; if (notestep > 31) notestep = 0; // tft.fillRect(tune * 3, 100, 20, 20, GREEN); for (byte x = 0; x < 127; x++) { testvol = x; vTaskDelay(300); } for (byte x = 0; x < 127; x++) { testvol = 127 - x; vTaskDelay(900); } // tft.fillRect(tune * 3, 100, 20, 20, BLUE); */ } } void DMAEvent() { static signed BaseType_t xYieldRequired; // xSemaphoreGiveFromISR(event_signal, NULL); // trigger if ((dma_get_isr_bits( DMA2, DMA_CH2) & 0x2)==1) { xQueueSendFromISR(dmaQueue, i2s_buffer, &xYieldRequired); } else { xQueueSendFromISR(dmaQueue, i2s_buffer_tophalf, &xYieldRequired); } dma_clear_isr_bits(DMA2, DMA_CH2); portEND_SWITCHING_ISR(xYieldRequired); } static void vFillBufferTask(void *pvParameters) { while (1) { if (xQueueReceive (dmaQueue, i2s_buffer_ptr , portMAX_DELAY) { // xSemaphoreTake(event_signal, 0); // portENTER_CRITICAL(); // gpio_write_bit(GPIOD, 2, 1); // test led on // byte flip=0; for (int cc = 0; cc < (buffer_size/2)-1 ; cc +2) { // flip=!flip; // if (flip==0) // { ulPhaseAccumulator_A[0] += ulPhaseIncrement_A[0] % SAMPLES_PER_CYCLE_FIXEDPOINT; // if (ulPhaseAccumulator_A[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) // { // ulPhaseAccumulator_A[0] -= SAMPLES_PER_CYCLE_FIXEDPOINT; // } ulPhaseAccumulator_B[0] += ulPhaseIncrement_B[0] % SAMPLES_PER_CYCLE_FIXEDPOINT; // if (ulPhaseAccumulator_B[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) // { // ulPhaseAccumulator_B[0] -= SAMPLES_PER_CYCLE_FIXEDPOINT; // } waveout_A[0] = (wavetable_A[ulPhaseAccumulator_A[0] >> 20] + wavetable_B[ulPhaseAccumulator_B[0] >> 20]) / 2; // waveout_A[0] = ( (waveout_A[0] * testvol) / 128); i2s_buffer_ptr[cc] = waveout_A[0]; // } // else // { ulPhaseAccumulator_A[1] += ulPhaseIncrement_A[1] % SAMPLES_PER_CYCLE_FIXEDPOINT; // if (ulPhaseAccumulator_A[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) // { // ulPhaseAccumulator_A[1] -= SAMPLES_PER_CYCLE_FIXEDPOINT; // } ulPhaseAccumulator_B[1] += ulPhaseIncrement_B[1] % SAMPLES_PER_CYCLE_FIXEDPOINT; // if (ulPhaseAccumulator_B[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) // { // ulPhaseAccumulator_B[1] -= SAMPLES_PER_CYCLE_FIXEDPOINT; // } waveout_A[1] = (wavetable_A[ulPhaseAccumulator_A[1] >> 20] + wavetable_B[ulPhaseAccumulator_B[1] >> 20]) / 2; waveout_A[1] = ( (waveout_A[1] * testvol2) / 128); i2s_buffer_ptr[cc+1] = waveout_A[1] ; // } } // gpio_write_bit(GPIOD, 2, 0); // test led off //xSemaphoreTake(event_signal, 0); // portEXIT_CRITICAL(); //vTaskSuspend(&TaskHandle_1 ); } // vTaskPrioritySet( &TaskHandle_1 , tskIDLE_PRIORITY + 0 ); } }

Мадиас
Пт 11 сентября 2015 г. 8:00 утра
Победители, спасибо за усилия!
К сожалению, это не будет функционировать, потому что данные не отправляются через MOSI (логический анал. --> SCK OK, WS OK, MOSI ---> Нет данных)

Я бы изменил некоторые вещи, вызванные компиляцией ошибок (очищенный код внизу):
Сначала линия static signed BaseType_t xYieldRequired;

Мадиас
Пт 11 сентября 2015 г. 8:25 утра
Хорошо, я изменил это: dma_setup_transfer(DMA2, DMA_CH2, &SPI3->regs->DR, DMA_SIZE_16BITS, i2s_buffer , DMA_SIZE_16BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_FROM_MEM | DMA_HALF_TRNS | DMA_TRNS_CMPLT));

Мадиас
Пт 11 сентября 2015 г. 8:54 утра
Хорошо, я переделаю код в свою рабочую копию, только внедряет код победителей, такой как xqueuesdenfromisr (dmaqueue, i2s_buffer, &xyieldrequired); , portend_switching_isr (xyieldrequired); В DMA IRQ и if (xqueuereceive (dmaqueue, i2s_buffer, portmax_delay)) в буферном задании.
Результат такой же, как и во многих вещах, которые я пытался на аутсорсинг буферного кода из DMA IRQ в задачу RTOS: Звук потрескивания. Если я настрою
(xqueuereceive (dmaqueue, i2s_buffer, portmax_delay))
другие (низкие приоритетные) задачи выполняются, но потрескивающий звук
Если я настрою
(xqueuereceive (dmaqueue, i2s_buffer, 0)))
Никакая задача с низким приоритетом не запустила бы.

Рабочая копия: (с потрескивающим звуком) /* Pins: #define BOARD_SPI3_NSS_PIN PA15 x timer #define BOARD_SPI3_SCK_PIN PB3 x timer #define BOARD_SPI3_MISO_PIN PB4 x timer #define BOARD_SPI3_MOSI_PIN PB5 x timer MCK Pins: I2S2MCK: PC6 Timer 8, Channel 1 I2S3MCK: PC7 Timer 8, Channel 2 #define BOARD_SPI1_NSS_PIN PA4 #define BOARD_SPI1_SCK_PIN PA5 #define BOARD_SPI1_MISO_PIN PA6 #define BOARD_SPI1_MOSI_PIN PA7 */ #include #include "libmaple/spi.h" #include "libmaple/dma.h" #include "header.h" #include #include #include #include #include #include "fonts/Arial14.h" #define TFT_DC PA1 #define TFT_CS PA0 #define rst PA2 #define BLACK 0x0000 #define RED 0xF800 #define GREEN 0x07E0 //#define BLUE 0x001F #define BLUE 0x102E #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define ORANGE 0xFD20 #define GREENYELLOW 0xAFE5 #define DARKGREEN 0x03E0 #define WHITE 0xFFFF // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, rst); ILI9341_due_gText t1(&tft); #define LED PD2 //#define buffer_size 256 #define buffer_size 64 int16_t i2s_buffer[buffer_size]; int16_t * i2s_buffer_tophalf = &i2s_buffer[buffer_size / 2]; int16_t * i2s_buffer_ptr; QueueHandle_t dmaQueue; SemaphoreHandle_t event_signal; xTaskHandle TaskHandle_1; byte melo[] = { 40, 52, 40, 52, 47, 59, 47, 59, 40, 52, 40, 52, 47, 59, 47, 59, 43, 55, 43, 55, 50, 62, 50, 62, 43, 55, 43, 55, 50, 69, 50, 69, }; byte wavecounter2 = 0; byte counter = 0; byte notestep = 0; byte dacval = 0; byte dacval2 = 0; volatile byte testvol = 127; volatile byte testvol2 = 127; byte freq = 30; void setup() { disableDebugPorts(); // need to use SPI3!!!! Serial.begin(9600); tft.begin(); tft.setRotation(iliRotation270); tft.fillScreen(BLUE); t1.defineArea(0, 0, 320, 240); t1.selectFont(Arial14); timer_set_mode(TIMER6, 2, TIMER_DISABLED); // disable pwm on pins fuer jeden setzen! gpio_set_mode(GPIOA, 15 , GPIO_AF_OUTPUT_PP); // SS pin gpio_set_mode(GPIOB, 3 , GPIO_AF_OUTPUT_PP); // sck gpio_set_mode(GPIOB, 4 , GPIO_INPUT_FLOATING); // miso gpio_set_mode(GPIOB, 5 , GPIO_AF_OUTPUT_PP); // mosi gpio_set_mode(GPIOC, 7 , GPIO_AF_OUTPUT_PP); // bck createNoteTable(SAMPLE_RATE); createWavetables(); ulPhaseIncrement_A[0] = nMidiPhaseIncrement[69]; // 69=440hz reference ulPhaseIncrement_A[1] = nMidiPhaseIncrement[69]; // 69=440hz reference pinMode (LED, OUTPUT); tft.fillRect(0, 0, 320, 15, RED); t1.setFontColor(WHITE, RED); t1.drawString("* ILI9341_due UTFT 240x320 Demo *", 47, 0); tft.fillRect(0, 226, 320, 240, tft.color565(64, 64, 64)); t1.setFontColor(YELLOW, tft.color565(64, 64, 64)); t1.drawString("bis dahin komm ich", gTextAlignBottomCenter, 227); i2s_begin(SPI3); // untere Funktion verwenden // ****DMA ****** dma_init(DMA2); spi_tx_dma_enable(SPI3); dma_attach_interrupt(DMA2, DMA_CH2, DMAEvent); spi_tx_dma_enable(SPI3); dma_setup_transfer(DMA2, DMA_CH2, &SPI3->regs->DR, DMA_SIZE_16BITS, i2s_buffer, DMA_SIZE_16BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT)); dma_set_num_transfers(DMA2, DMA_CH2, buffer_size); dma_set_priority(DMA2, DMA_CH2, DMA_PRIORITY_VERY_HIGH); dma_enable(DMA2, DMA_CH2);// enable transmit testvol = 127; dmaQueue = xQueueCreate ( 2, sizeof (int16_t) ); vSemaphoreCreateBinary( event_signal ); // Create the semaphore xSemaphoreTake(event_signal, 0); // Take semaphore after creating it. xTaskCreate(vFillBufferTask, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 5, &TaskHandle_1); xTaskCreate(vMusicTask, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler(); } void loop() { } static void vMusicTask(void *pvParameters) { while (1) { freq++; if (freq == 90) freq = 30; testvol = 127; ulPhaseIncrement_A[0] = nMidiPhaseIncrement[byte(freq)]; // should be 440hz ulPhaseIncrement_B[0] = nMidiPhaseIncrement[byte(freq)]; ulPhaseIncrement_A[1] = nMidiPhaseIncrement[byte(90 - freq)]; // should be 440hz ulPhaseIncrement_B[1] = nMidiPhaseIncrement[byte(90 - freq)]; vTaskDelay(100); } } void DMAEvent() { static signed portBASE_TYPE xYieldRequired; // xSemaphoreGiveFromISR(event_signal, NULL); // trigger // if ((dma_get_isr_bits( DMA2, DMA_CH2) & 0x2) == 1) { xQueueSendFromISR(dmaQueue, i2s_buffer, &xYieldRequired); // } // else { // xQueueSendFromISR(dmaQueue, i2s_buffer_tophalf, &xYieldRequired); // } portEND_SWITCHING_ISR(xYieldRequired); dma_clear_isr_bits(DMA2, DMA_CH2); } static void vFillBufferTask(void *pvParameters) { while (1) { if (xQueueReceive (dmaQueue, i2s_buffer , portMAX_DELAY)) { // gpio_write_bit(GPIOD, 2, 1); // test led on byte flip=0; // gpio_write_bit(GPIOD, 2, 1); // test led on for (int cc = 0; cc < buffer_size; cc ++) { flip=!flip; if (flip==0) { ulPhaseAccumulator_A[0] += ulPhaseIncrement_A[0]; if (ulPhaseAccumulator_A[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_A[0] =0; } ulPhaseAccumulator_B[0] += ulPhaseIncrement_B[0] ; if (ulPhaseAccumulator_B[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_B[0] =0; } waveout_A[0] = (wavetable_A[ulPhaseAccumulator_A[0] >> 20] + wavetable_B[ulPhaseAccumulator_B[0] >> 20]) / 2; waveout_A[0] = ( (waveout_A[0] * testvol) / 128); i2s_buffer[cc] = waveout_A[0]; // half transfer } else { ulPhaseAccumulator_A[1] += ulPhaseIncrement_A[1] ; if (ulPhaseAccumulator_A[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_A[1] -= SAMPLES_PER_CYCLE_FIXEDPOINT; } ulPhaseAccumulator_B[1] += ulPhaseIncrement_B[1] ; if (ulPhaseAccumulator_B[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_B[1] -= SAMPLES_PER_CYCLE_FIXEDPOINT; } waveout_A[1] = (wavetable_A[ulPhaseAccumulator_A[1] >> 20] + wavetable_B[ulPhaseAccumulator_B[1] >> 20]) / 2; waveout_A[1] = ( (waveout_A[1] * testvol2) / 128); i2s_buffer[cc ] = waveout_A[1] ; } // gpio_write_bit(GPIOD, 2, 0); // test led on } } } }

Мадиас
Пт 11 сентября 2015 г. 11:18 утра
Хм.
Тем временем я обдумываю проект.
Может быть, было бы лучше (как мой первый план), оставляя «звуковой двигатель» на PIC32MX250 (код почти написан и работает без кликов) и использование STM32 в качестве устройства управления для всего остального: человеческий интерфейс, TFT, OLED, Serial-Midi , USB-MIDI, управление хранением (патчи, волны, даже на SD-карту или SPI-Flash) через RTOS
Хороший 4-канальный аудио-двигатель, даже с лучшими оптимизациями кода, потребует около 60-80% MCU (если не STM32F7 ;) ), так что это было бы неисправное компромиссное упаковку все в один STM32F103 (например, лучшее качество звука, но абсолютно медленное обновление TFT, висящие миди ...) .
Большое преимущество большинства MCU (STM32F1, PIC32MX...): Они потрясающие дешевые!
Это также экономический факт: у меня дома около 10 Pic32mx250 :)
Я не должен переосмыслить колесо: в моем бывшем проекте построил синтезатор с Tiva-TMC123 в качестве управляющего устройства и 4 Mini Arduino в качестве звуковых устройств (каждая с параллельным 8-битным ЦАП). Даже человеческий интерфейс контролировался ATMEGA328 (поэтому круговая плата интерфейса человека была независимой только два провода на главной плате) . Интересная вещь: i2c был лучшим протоколом связи между мини -и Tiva. Поэтому я бы сделал то же самое с STM32F1 и PIC32MX --> через I2C (потому что я использую все порты SPI на картинке как i2s)
Недостаток аутсорсинговой загрузки в серверы MCU: обновление прошивки. Таким образом, вы измените ядро, вы должны обновить прошивку на каждом устройстве. (Плохо, если я планирую продавать синтезаторы, обновление прошивки было бы слишком сложным для среднего пользователя)

victor_pv
Пт 11 сентября 2015 12:44
Мадиас написал:Хм.
Тем временем я обдумываю проект.
Может быть, было бы лучше (как мой первый план), оставляя «звуковой двигатель» на PIC32MX250 (код почти написан и работает без кликов) и используя STM32 в качестве устройства управления для всего остального: человеческий интерфейс, TFT, OLED, Serial-Midi , USB-MIDI, управление хранением (патчи, волны, даже на SD-карту или SPI-Flash) через RTOS
Хороший 4-канальный аудио-двигатель, даже с лучшими оптимизациями кода, потребует около 60-80% MCU (если не STM32F7 ;) ), так что это было бы неисправное компромиссное упаковку все в один STM32F103 (например, лучшее качество звука, но абсолютно медленное обновление TFT, висящие миди ...) .
Большое преимущество большинства MCU (STM32F1, PIC32MX...): Они потрясающие дешевые!
Это также экономический факт: у меня дома около 10 Pic32mx250 :)
Я не должен переосмыслить колесо: в моем бывшем проекте построил синтезатор с Tiva-TMC123 в качестве управляющего устройства и 4 Mini Arduino в качестве звуковых устройств (каждая с параллельным 8-битным ЦАП). Даже человеческий интерфейс контролировался ATMEGA328 (поэтому круговая плата интерфейса человека была независимой только два провода на главной плате) . Интересная вещь: i2c был лучшим протоколом связи между мини -и Tiva. Поэтому я бы сделал то же самое с STM32F1 и PIC32MX --> через I2C (потому что я использую все порты SPI на картинке как i2s)
Недостаток аутсорсинговой загрузки в серверы MCU: обновление прошивки. Таким образом, вы измените ядро, вы должны обновить прошивку на каждом устройстве. (Плохо, если я планирую продавать синтезаторы, обновление прошивки было бы слишком сложным для среднего пользователя)

Мадиас
Пт 11 сентября 2015 г. 14:19
Спасибо, что попробовали это, я должен отправить вам DAC PT8211 :) (Лучше: я заказываю для вас 20-30 пунктов на Али, это дешевле, чем отправлять один ПК из Австрии в США ;) )
Даже без I2S ЦАП, это легко наблюдать: только с логическим анализатором Saleae и установите его на i2s (я разместил настройки для PT8211 в другой потоке) и используя слева и пишную волну вправо, так что В протоколе данные подсчитывают/вниз (в порядке, чтобы опробовать только 256 значений, легко обрабатывать протокол). Я думаю, что мы все слишком меньше используем логический анализатор :)

О обновлении прошивки:
Это моя старая идея, играя с досками Nucleo: ST-Link V2.1 Подключитесь к компьюте&Отбросить файл *bin для загрузки. Это должно быть (тихо) легкое решение для «перетаскивания&бросить "загрузчик. Таким образом, этот специальный загрузчик может быть загружен как «последний шаг» на готовом продукте. Я думаю, что многие из нас будут работать не только на себя, но и создавать проекты для семьи, друзей или даже коммерческого. Таким образом, этот конечный пользователь может легко загрузить новую прошивку через перетаскивание&бросить загрузчик. Должно быть возможно - или? ;)
Я на свадьбе в эти выходные, так что в понедельник я снова нахожусь в бегах.

Приветствует
Матиас

victor_pv
Пт 11 сентября 2015 г. 16:43
Мадиас написал:Спасибо, что попробовали это, я должен отправить вам DAC PT8211 :) (Лучше: я заказываю для вас 20-30 пунктов на Али, это дешевле, чем отправлять один ПК из Австрии в США ;) )
Даже без I2S ЦАП, это легко наблюдать: только с логическим анализатором Saleae и установите его на i2s (я разместил настройки для PT8211 в другой потоке) и используя слева и пишную волну вправо, так что В протоколе данные подсчитывают/вниз (в порядке, чтобы опробовать только 256 значений, легко обрабатывать протокол). Я думаю, что мы все слишком меньше используем логический анализатор :)

О обновлении прошивки:
Это моя старая идея, играя с досками Nucleo: ST-Link V2.1 Подключитесь к компьюте&Отбросить файл *bin для загрузки. Это должно быть (тихо) легкое решение для «перетаскивания&бросить "загрузчик. Таким образом, этот специальный загрузчик может быть загружен как «последний шаг» на готовом продукте. Я думаю, что многие из нас будут работать не только на себя, но и создавать проекты для семьи, друзей или даже коммерческого. Таким образом, этот конечный пользователь может легко загрузить новую прошивку через перетаскивание&бросить загрузчик. Должно быть возможно - или? ;)
Я на свадьбе в эти выходные, так что в понедельник я снова нахожусь в бегах.

Приветствует
Матиас

Мадиас
Пт 11 сентября 2015 г., 21:06
You said that when using the half transfer flag, it does not send anything at all right?

victor_pv
Сб 12 сентября 2015 г. 14:21
Я обнаружил, что эта функция всегда читает 0, по -видимому, несмотря ни на что:
dma_get_isr_bits (dma2, dma_ch2);

Таким образом, DMA ISR всегда помещает одну и ту же половину буфера в очередь, в результате чего контроллер DMA отправляет 64 нулей и 64 байта с данными, и это повторяется снова и снова.

Я пробовал кучу разных способов чтения этой ценности, и она всегда терпит неудачу. Я знаю, что один и тот же код отлично работает для каналов SPI1 и SPI2, потому что я использовал DMA с этими двумя портами, и если бы это всегда было чтение 0, код был бы навсегда в первой передаче.

Но я не могу найти то, что не читает никакой ценности в этом случае. Я пытался прочитать его с переменной, объявленной нестабильной, объявленной статичной и не знаю, что еще, и, кажется, всегда делает то же самое.
Я не уверен, что это компилятор, оптимизирующий код, или что... Я могу попытаться изменить опцию оптимизации моего компилятора на -o0 и попробую еще раз...

Изменить: не могу выяснить, почему флаги не могут быть прочитаны, поэтому в настоящее время я просто использовал еще одну переменную FLIP, чтобы решить, какой указатель отправить.
Кажется, хорошо работает, насколько может показать Saleae, если у вас есть шанс проверить его с аудио:
/* Pins: #define BOARD_SPI3_NSS_PIN PA15 x timer #define BOARD_SPI3_SCK_PIN PB3 x timer #define BOARD_SPI3_MISO_PIN PB4 x timer #define BOARD_SPI3_MOSI_PIN PB5 x timer MCK Pins: I2S2MCK: PC6 Timer 8, Channel 1 I2S3MCK: PC7 Timer 8, Channel 2 #define BOARD_SPI1_NSS_PIN PA4 #define BOARD_SPI1_SCK_PIN PA5 #define BOARD_SPI1_MISO_PIN PA6 #define BOARD_SPI1_MOSI_PIN PA7 */ #include #include "libmaple/spi.h" #include "libmaple/dma.h" #include "header.h" #include #include #include #include #include #include "fonts/Arial14.h" #define TFT_DC PA1 #define TFT_CS PA0 #define rst PA2 #define BLACK 0x0000 #define RED 0xF800 #define GREEN 0x07E0 //#define BLUE 0x001F #define BLUE 0x102E #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define ORANGE 0xFD20 #define GREENYELLOW 0xAFE5 #define DARKGREEN 0x03E0 #define WHITE 0xFFFF // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, rst); ILI9341_due_gText t1(&tft); #define LED PD2 //#define buffer_size 2 #define buffer_size 128 int16_t i2s_buffer[buffer_size]; int16_t *i2s_bottom = i2s_buffer; int16_t *i2s_top = &i2s_buffer[buffer_size / 2]; static int16_t * i2s_buffer_ptr; QueueHandle_t dmaQueue; static void inline __attribute__((interrupt)) DMAEvent(); volatile byte flip2 = 0; SemaphoreHandle_t event_signal; xTaskHandle TaskHandle_1; byte melo[] = { 40, 52, 40, 52, 47, 59, 47, 59, 40, 52, 40, 52, 47, 59, 47, 59, 43, 55, 43, 55, 50, 62, 50, 62, 43, 55, 43, 55, 50, 69, 50, 69, }; byte wavecounter2 = 0; byte counter = 0; byte notestep = 0; byte dacval = 0; byte dacval2 = 0; volatile byte testvol = 127; volatile byte testvol2 = 127; byte freq = 30; void setup() { disableDebugPorts(); // need to use SPI3!!!! Serial.begin(9600); tft.begin(); tft.setRotation(iliRotation270); tft.fillScreen(BLUE); t1.defineArea(0, 0, 320, 240); t1.selectFont(Arial14); timer_set_mode(TIMER6, 2, TIMER_DISABLED); // disable pwm on pins fuer jeden setzen! gpio_set_mode(GPIOA, 15 , GPIO_AF_OUTPUT_PP); // SS pin gpio_set_mode(GPIOB, 3 , GPIO_AF_OUTPUT_PP); // sck gpio_set_mode(GPIOB, 4 , GPIO_INPUT_FLOATING); // miso gpio_set_mode(GPIOB, 5 , GPIO_AF_OUTPUT_PP); // mosi gpio_set_mode(GPIOC, 7 , GPIO_AF_OUTPUT_PP); // bck createNoteTable(SAMPLE_RATE); createWavetables(); ulPhaseIncrement_A[0] = nMidiPhaseIncrement[69]; // 69=440hz reference ulPhaseIncrement_A[1] = nMidiPhaseIncrement[69]; // 69=440hz reference pinMode (LED, OUTPUT); tft.fillRect(0, 0, 320, 15, RED); t1.setFontColor(WHITE, RED); t1.drawString("* ILI9341_due UTFT 240x320 Demo *", 47, 0); tft.fillRect(0, 226, 320, 240, tft.color565(64, 64, 64)); t1.setFontColor(YELLOW, tft.color565(64, 64, 64)); t1.drawString("bis dahin komm ich", gTextAlignBottomCenter, 227); i2s_begin(SPI3); // untere Funktion verwenden // ****DMA ****** dma_init(DMA2); spi_tx_dma_enable(SPI3); dma_attach_interrupt(DMA2, DMA_CH2, DMAEvent); spi_tx_dma_enable(SPI3); dma_setup_transfer(DMA2, DMA_CH2, &SPI3->regs->DR, DMA_SIZE_16BITS, i2s_buffer, DMA_SIZE_16BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_FROM_MEM | DMA_HALF_TRNS | DMA_TRNS_CMPLT)); dma_set_num_transfers(DMA2, DMA_CH2, buffer_size); dma_set_priority(DMA2, DMA_CH2, DMA_PRIORITY_VERY_HIGH); dma_enable(DMA2, DMA_CH2);// enable transmit testvol = 127; dmaQueue = xQueueCreate ( 2, sizeof (int16_t*) ); vSemaphoreCreateBinary( event_signal ); // Create the semaphore xSemaphoreTake(event_signal, 0); // Take semaphore after creating it. xTaskCreate(vFillBufferTask, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &TaskHandle_1); xTaskCreate(vMusicTask, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler(); } void loop() { } static void vMusicTask(void *pvParameters) { while (1) { freq++; if (freq == 90) freq = 30; testvol = 127; ulPhaseIncrement_A[0] = nMidiPhaseIncrement[byte(freq)]; // should be 440hz ulPhaseIncrement_B[0] = nMidiPhaseIncrement[byte(freq)]; ulPhaseIncrement_A[1] = nMidiPhaseIncrement[byte(90 - freq)]; // should be 440hz ulPhaseIncrement_B[1] = nMidiPhaseIncrement[byte(90 - freq)]; vTaskDelay(100); /* byte tune = melo[notestep]; ulPhaseIncrement_A[0] = nMidiPhaseIncrement[byte(tune)]; ulPhaseIncrement_B[0] = nMidiPhaseIncrement[byte(tune) + 7]; ulPhaseIncrement_A[1] = nMidiPhaseIncrement[byte(tune + 12)]; ulPhaseIncrement_B[1] = nMidiPhaseIncrement[byte(tune) + 19]; // Serial.println(nMidiPhaseIncrement[byte(tune)] ); notestep += 1; if (notestep > 31) notestep = 0; // tft.fillRect(tune * 3, 100, 20, 20, GREEN); for (byte x = 0; x < 127; x++) { testvol = x; vTaskDelay(300); } for (byte x = 0; x < 127; x++) { testvol = 127 - x; vTaskDelay(900); } // tft.fillRect(tune * 3, 100, 20, 20, BLUE); */ } } static inline void DMAEvent() { static signed portBASE_TYPE xYieldRequired; //volatile uint8 isr = dma_get_isr_bits( DMA2, DMA_CH2); //volatile dma_irq_cause event = dma_get_irq_cause(DMA2, DMA_CH2); // xSemaphoreGiveFromISR(event_signal, NULL); // trigger if (flip2 == 0 ) { gpio_write_bit(GPIOD, 2, 0); // test led off xQueueSendFromISR(dmaQueue, (void*)&i2s_bottom, &xYieldRequired); } else { gpio_write_bit(GPIOD, 2, 1); // test led on xQueueSendFromISR(dmaQueue, (void*)&i2s_top, &xYieldRequired); } dma_clear_isr_bits(DMA2, DMA_CH2); flip2 = !flip2; portEND_SWITCHING_ISR(xYieldRequired); } static void vFillBufferTask(void *pvParameters) { while (1) { if (xQueueReceive (dmaQueue, &i2s_buffer_ptr , portMAX_DELAY)) { // xSemaphoreTake(event_signal, 0); // portENTER_CRITICAL(); /* Serial.println ((uint32_t)i2s_buffer_ptr); Serial.println ((uint32_t)i2s_bottom); Serial.println ((uint32_t)i2s_top); Serial.println (); */ // gpio_write_bit(GPIOD, 2, 1); // test led on byte flip = 0; for (int cc = 0; cc < (buffer_size / 2)-1 ; cc += 2) { ulPhaseAccumulator_A[0] += ulPhaseIncrement_A[0] ; if (ulPhaseAccumulator_A[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_A[0] = 0; } ulPhaseAccumulator_B[0] += ulPhaseIncrement_B[0] ; if (ulPhaseAccumulator_B[0] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_B[0] = 0; } waveout_A[0] = (wavetable_A[ulPhaseAccumulator_A[0] >> 20] + wavetable_B[ulPhaseAccumulator_B[0] >> 20]) / 2; // waveout_A[0] = ( (waveout_A[0] * testvol) / 128); i2s_buffer_ptr[cc] = waveout_A[0]; ulPhaseAccumulator_A[1] += ulPhaseIncrement_A[1] ; if (ulPhaseAccumulator_A[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_A[1] = 0; } ulPhaseAccumulator_B[1] += ulPhaseIncrement_B[1] ; if (ulPhaseAccumulator_B[1] > SAMPLES_PER_CYCLE_FIXEDPOINT) { ulPhaseAccumulator_B[1] = 0; } waveout_A[1] = (wavetable_A[ulPhaseAccumulator_A[1] >> 20] + wavetable_B[ulPhaseAccumulator_B[1] >> 20]) / 2; waveout_A[1] = ( (waveout_A[1] * testvol2) / 128); i2s_buffer_ptr[cc+1] = waveout_A[1] ; } // gpio_write_bit(GPIOD, 2, 0); // test led off //xSemaphoreTake(event_signal, 0); // portEXIT_CRITICAL(); //vTaskSuspend(&TaskHandle_1 ); } // vTaskPrioritySet( &TaskHandle_1 , tskIDLE_PRIORITY + 0 ); } }

Мадиас
Солнце 13 сентября 2015 г., 7:40
Странно, я обязательно получу хотя бы значение «3» назад (перевод полная+перевод половина). Должен проверить это завтра (я все еще не дома).
Я немного подумал о кликах и всплесках, которые у меня есть с более высоким буфером, возможно, мне следует установить DMA-IRQ на более высокий приоритет?

victor_pv
Солнце 13 сентября 2015 г., 22:42
Мадиас написал:Странно, я обязательно получу хотя бы значение «3» назад (перевод полная+перевод половина). Должен проверить это завтра (я все еще не дома).
Я немного подумал о кликах и всплесках, которые у меня есть с более высоким буфером, возможно, мне следует установить DMA-IRQ на более высокий приоритет?

Мадиас
Пн 14 сентября 2015 г. 5:52 утра
Я пробую это сегодня!
Один подумать: вы используете также «круговой буфер» в своем первом проекте? Я не уверен, но я думаю, что где-то я прочитал, что в круговом буфере полу-перенос (или полная передача) DMA не установит флаг.

Мадиас
Пн 14 сентября 2015 г. 9:33 утра
ОК, Виктор, мы приближаемся! :)
Я попробовал ваш последний код, и он работает гладко на обоих каналах без отсевания/кликов.
Кроме того, я включил фиктивную задачу TFT (просто печать некоторые значения) с низким приоритетом. Итак, у меня есть четыре задачи: audio_engine, melody, serial и tft.
По соображениям безопасности (возможно, нет необходимости, но я включил его, чтобы помнить), я сделал nvic_irq_set_priority(NVIC_DMA2_CH2, 1); // DMA priority test

Мадиас
Пн 14 сентября 2015 г. 14:16
Хорошо,
Теперь я изменил DMA IRQ на: static inline void DMAEvent() { static signed portBASE_TYPE xYieldRequired; if (dma_get_isr_bits( DMA2, DMA_CH2) == 3 ) { gpio_write_bit(GPIOD, 2, 0); // test led off xQueueSendFromISR(dmaQueue, (void*)&i2s_bottom, &xYieldRequired); } else { gpio_write_bit(GPIOD, 2, 1); // test led on xQueueSendFromISR(dmaQueue, (void*)&i2s_top, &xYieldRequired); } dma_clear_isr_bits(DMA2, DMA_CH2); // flip2 = !flip2; portEND_SWITCHING_ISR(xYieldRequired); }

victor_pv
Вторник 15 сентября 2015 г. 12:59
Мадиас написал:ОК, Виктор, мы приближаемся! :)
Я попробовал ваш последний код, и он работает гладко на обоих каналах без отсевания/кликов.
Кроме того, я включил фиктивную задачу TFT (просто печать некоторые значения) с низким приоритетом. Итак, у меня есть четыре задачи: audio_engine, melody, serial и tft.
По соображениям безопасности (возможно, нет необходимости, но я включил его, чтобы помнить), я сделал nvic_irq_set_priority(NVIC_DMA2_CH2, 1); // DMA priority test

Мадиас
Вторник 15 сентября 2015 г., 21:01
Странно, что с переключением между DMA_BIT 5 и DMA_BIT3 в коде Один канал искажен.
Тем временем я создал полный лист для своего проекта. Только около 3-5 булавок бесплатно :)
Хорошо, я не очень экономный с булавками, поэтому каждая кнопка (только 5) получает собственную булавку, и мой энкодер (5) нуждается в 10 контактах (поэтому я могу настроить для них IRQ, что лучше для распознавания движений с разными скоростями, я В течение нескольких месяцев назад он опубликовал код с несколькими экодерками-ACC: ViewTopic.PHP?F = 18&t = 15 ), см. Прикрепленный PDF
Я также использую вместо внешнего (управление!) ЦАП для моей платы фильтров The Swm Pins, но я буду ждать, пока не будут отправлены мои фильтрующие доски (я сделал фильтрацию LP в цепи, поэтому SWM должен работать - с более высокой частотой)
Так что в целом мой проект был бы возможно только с одним STM32 (на чертежной доске).

victor_pv
Ср. 16 сентября 2015 г., 2:59
Мадиас написал:Странно, что с переключением между DMA_BIT 5 и DMA_BIT3 в коде Один канал искажен.
Тем временем я создал полный лист для своего проекта. Только около 3-5 булавок бесплатно :)
Хорошо, я не очень экономный с булавками, поэтому каждая кнопка (только 5) получает собственную булавку, и мой энкодер (5) нуждается в 10 контактах (поэтому я могу настроить для них IRQ, что лучше для распознавания движений с разными скоростями, я В течение нескольких месяцев назад он опубликовал код с несколькими экодерками-ACC: ViewTopic.PHP?F = 18&t = 15 ), см. Прикрепленный PDF
Я также использую вместо внешнего (управление!) ЦАП для моей платы фильтров The Swm Pins, но я буду ждать, пока не будут отправлены мои фильтрующие доски (я сделал фильтрацию LP в цепи, поэтому SWM должен работать - с более высокой частотой)
Так что в целом мой проект был бы возможно только с одним STM32 (на чертежной доске).

Мадиас
Ср. 16 сентября 2015 г. 5:38 утра
Просто для быстрого (должен идти на работу):
Вот XLS - Файл штифта, так что вы можете отредактировать его для собственных проектов:
Кстати: у меня есть ветеринарная доска (так же, как у вас!но я думаю, что это слишком хорошо, чтобы использовать его в этом проекте (хорошо, мне это нравится как основная доска для разработки!)
Использование кнопок с разделителем напряжения: может быть, идея с 5 кнопками (у меня дома много резисторных сет. (Немного другое основное напряжение = полное ложное значения).

victor_pv
Чт 17 сентября 2015 г., 3:17 утра
Мадиас написал:Просто для быстрого (должен идти на работу):
Вот XLS - Файл штифта, так что вы можете отредактировать его для собственных проектов:
Кстати: у меня есть ветеринарная доска (так же, как у вас!но я думаю, что это слишком хорошо, чтобы использовать его в этом проекте (хорошо, мне это нравится как основная доска для разработки!)
Использование кнопок с разделителем напряжения: может быть, идея с 5 кнопками (у меня дома много резисторных сет. (Немного другое основное напряжение = полное ложное значения).

Мадиас
Чт 17 сентября 2015 г. 14:31
Важное обновление (по крайней мере для меня)
Я дублирует I2S и код DMA (+задачи), чтобы получить два PT8211, поэтому я ближе к своей цели. Получить 4 независимых результатов. (Используя SPI2 (I2S) и SPI3 (I2S-2))
Статус: Работающий!
Забавный факт (По крайней мере, с сегодняшней точки зрения):
Второй Pt8211 всегда был шумным, и сигнал был тише, как только выходить из него 8-бит.
Я потратил 2 часа: (re) Написание кода, изучил правильные булавки, обменял PT8211....
В качестве последнего испытания я взял все кабели с первого PT до второго: тот же шум!
В отчаянии я в последний раз посмотрел на кабели и прыжки на макетинг - Vola! Джампер VCC для второго PT был на отверстии рядом с правым.
Заключение: Даже с наиболее сложным кодом решение может быть простой неправильно установленной перемычкой :)
Значит: PT работал без VCC, поэтому, если бы он не сработал, я бы быстрее пришел к ошибке....

Мадиас
Пт 18 сентября 2015 г. 15:34
Хорошо, в ожидании моих фильтров -досок (я надеюсь, что они будут отправлены в течение следующих 2 недель), я подумал еще о распиновки:
Кнопки, как предложил Виктор, теперь находятся на АЦП с разделителями напряжения (так что у меня около 10 кнопок)
Изображение
Рукоявка выше-это полуавто. Просто перетащите «Использование» в списке, отсортированные по булавкам, и автоматическое, показанное в «Просмотке доски». Недостаток: цвета фона не клонированы (я понятия не имею, как это работает в Excel)
Итак, моя последняя установка:
2 Pt8211 ЦАП (4 независимых выходов)
10 кнопок (одна как нажмите энкодер)
5 энкодеров (один с кликом)
1 TFT ILI9341 с прикосновением
1 OLED (показывает функцию/значения энкодера)
1 Уинбонд Spi-Seeprom
1 23LC512 I2C-IEPROM (больше циклов записи/стирания)
SD-карта (от TFT)
Серийный миди
USB MIDI
Все элементы управления платой фильтров с помощью ШИМ (4x том, 4x отсечка и 1x резонанс (используется для всех голосов, нет необходимости в 4 независимых ресторанах)))
ST-Link Cable Out (самый простой способ обновления)

Мадиас
Вторник 29 сентября 2015 г., 19:35
Хорошо, вчера был мой самый темный день для этого проекта:
Мои доски для фильтров прибыли, я паял их, а потом: ничего. Проведен в целом около 12 часов (представьте себе: у меня есть жена, 3-летняя дочь и работа на полный рабочий день, так что время для меня очень * дорого) без решения. Я действительно думал сдаться даже со всей электроникой.
Сегодня я даю себе еще одну попытку, изучал мои файлы KICAD, оригинальные и таблицы, и я нашел это:

Снова супер глупый противный: я смутил один (!) 470R Резистор с крышкой 470PF. Ошибка была также в моем макете KICAD, и все остановилось на работе.
Хорошо, с рабочей платой фильтров (я полностью разгромил первую, ради небеса DirtyPcb отправил вам около 12 досок), я провел некоторое звуковое тестирование и упомянул, что с SWM нет шансов (3.3 В против 5 В (плата фильтров для 5 В)), поэтому я должен использовать Spi-Octal DAC (LT1660), не имеющего большого значения, потому что у меня есть их дома, но немного противно программировать: spi tft (и и SD) находится на Div2 и SPI-DAC потребности Div4. Пробовал много вещей, и самое лучшее для стабильности (без висящего TFT или ЦАП) - иметь дело с Div4.

Несколько слов о звуке платы фильтров: просто *потрясающе * !!! Настоящий аналоговый 4-полюсный низкий проход с дополнительным аналоговым VCA на борту. И самое лучшее: абсолютно никакого шума! Так что все мои сомнения исчезли....
Быстрая картинка настройки тестирования, плата фильтров - это белая печатная плата:
Изображение

Вассилис
Вторник 29 сентября 2015 г. 20:57
Хороший!
Я хотел бы увидеть видео демонстрацию вашей доски, когда вы закончите ее!

пса. У меня есть жена, два Daugthers 13 и 11 лет, работа на полный рабочий день, и я работаю в химической промышленности с тремя сменами. Я знаю, что означает «свободное время» ...
Но... Когда вы любите что -то, вы можете найти время для этого :)

victor_pv
Ср 30 сентября 2015 г. 1:46
Вассилис написал:Хороший!
Я хотел бы увидеть видео демонстрацию вашей доски, когда вы закончите ее!

Мадиас
Чт 01 октября 2015 г., 21:47
Я сделаю демо на YouTube, если готов представить что -то лучшее :)
ОБНОВЛЯТЬ:

ЦАП - ШИМ

Как я писал ранее, SWM как «аналоговое управление» для меня не является вариантом (3.3 против 5 В и слишком низкая частота ШИМ), поэтому я решил использовать SPI DAC LTC1660 (или LTC1665 (8 или 10 бит))).
Но у меня есть: 4x среза, 4x тома + общий канал для резонанса = 9 выходов. К сожалению, LTC - всего лишь восьмиугольный ЦАП. К счастью, STM32F103RCT имеет 2 бортовых ЦАП, но один (PA5) конфликт со SPI SCK. Но другой "чистый". Итак, у меня есть 9 аналоговых выходов :)

Отображать
Я думаю, что оставляю эту идею с TFT ILI9341 по нескольким причинам: замедлить систему, «негабаритный» - мне не нужны цвета для этого проекта, и на солнце не очень приятно видеть (яркость, просмотр угол). Поэтому я решил использовать большой монохромный дисплей 128x64 (ST7920, я написал библиотеку для этого --> См. Main Repo) как основной дисплей и вторичный I2C-oled (значения печати для кодеров).

RTOS
Я думаю, что я закончил с RTO для этого проекта: у меня слишком много проблем с ним. Хорошо, может быть.
Проблемы до сих пор: моя графическая библиотека LCD S7920 не будет работать с RTOS. Линии, коробки и другие графические элементы работают, но шрифт только мусор. Даже в коде установки я могу использовать шрифт. Поэтому я думаю, что должен быть большой конфликт памяти, особенно с библиотеками и большими массивами (например, шрифтами) (у меня было это при использовании библиотеки Adafruit ILI9341, но я поднимаю размер стека для задачи). Другая причина заключается в том, что я могу использовать около 90% письменного кода из моего бывшего проекта (с Tiva-TMC123), я справился со всем с таймерами. Следующая сделка: в RTO нет реальной интеграции с аппаратным таймером, а минимальная задержка составляет 1 мс (мне нужен NS). Я исследовал обе проблемы на форумах RTOS, нашел много записей, но нет решения.
редактировать: Получил ЖК -библиотеку для работы. Проблема заключалась в переменной «статической длинной XY» в другой задаче (ОК, кажется, что RTO не любят статические переменные в задачах....)
Но у меня есть вопрос:
В ЖК -библиотеке есть несколько задержек (x), я думаю, что это не подходит для RTOS (Vdelay), но я не могу справиться с этим (пытался использовать Vdelay в библиотеке, но она не будет функционировать)

victor_pv
Пт 02 октября 2015 г. 1:45
Чтобы использовать Vdelay в библиотеке, вам необходимо включить RTOS в файл CPP библиотеки.
Я провел некоторое тестирование, перезарязив библиотеку SPI и ILI9163 для COO, и должен был сделать это. Я не пробовал с Freertos, но я уверен, что был бы таким же случаем.

Тем не менее, вы можете сделать все это с таймерами, нет причин для RTOS. Я бы использовал RTOS, если бы это упростила мою жизнь, но не более сложной ;)
Libmaple Systick ISR может быть настроен для обратного вызова вашей собственной функции каждые 1 мс, если это поможет вам запланировать некоторые задачи без использования RTO, а затем вы можете использовать любой другой таймер с гораздо более высокой частотой для других вещей. Дайте, чем вам не нужны таймеры для PWM, у вас должно быть много таймеров для этого.

О звуке, даже если это просто белый шум, я хотел бы его услышать, уделяло нам так много головных болей, чтобы заставить DMA i2s работать!! :ржу не могу:

Ах еще одна вещь, вы можете заблокировать планировщик RTOS во время чувствительных к времени функциям, так что это не оставляет определенного определения, когда вы не хотите, чтобы он был. Я забыл имена функций, но есть 2, один, один, чтобы заблокировать планировщик, а один, чтобы разблокировать его снова. Прерывания не будут затронуты. Вы можете сделать это, чтобы проверить, если вы подозреваете, что планировщик влияет на ваши функции каким -либо образом, поэтому вы блокируете, запускаете свой чувствительный код, разблокируйтесь снова.

Мадиас
Вт 20 октября 2015 г. 15:37
ОК, маленькое обновление:
В основном из модулей было построено:
Изображение
Изображение
Изображение
Изображение
Изображение
Изображение

Мадиас
Вт 20 октября 2015 г., 21:06
Быстрое и грязное видео (человеческий интерфейс - нет звука)
https: // youtu.be/tvv4jb7tqec

Ахулл
Вт 20 октября 2015 г., 22:05
Мадиас написал:Быстрое и грязное видео (человеческий интерфейс - нет звука)
https: // youtu.be/tvv4jb7tqec

Мадиас
Вт 17 ноября 2015 г., 17:03
Хорошо, этот проект действительно один шаг вперед и два шага назад:/
Я выгнал RTO из проекта, только проблемы с использованными библиотеками, и я не переписываю время каждого, и мне действительно лучше в таймерах с этим проектом.
ОК, мне удалось преобразовать все обратно, получил интерфейс запустить (кодеры, ручки, светодиоды...), Получил звук DMA для всех 4 каналов, работающих без кликов, все другие ЦАП (для VCA, отсечение...).
А теперь:
Я добавил еще несколько переменных и функций, и все шрифты на дисплее ST7920 - мусор. Все работает нормально, только шрифт - это проблема: так что печатные линии, круги, все в порядке. Так что я думаю, что должна быть утечка памяти и/или неправильные указатели. Но это происходит только с библиотекой ST8920, а не с Adafruit OLED, это ясно работает. Таким образом, чем больше кода (переменные) я вкладываю в него, тем больше мусора выходит, если я удаляю дополнительный код, шрифт становится правильным. Полностью расстраивает.
Я полагаю, что должны быть некоторые ошибки с разговором всего проглемема из оригинальной библиотеки, но я бы не подумал, что кто -то здесь может помочь мне, но я поместил здесь код библиотеки:
Что я сделал, так это сравнить обработку шрифта Adafruit GFX и из моей библиотеки (Extern Const... и так далее) без повезло.

Редактировать: во имя библиотеки есть «RTOS», но там больше нет RTOS.
с уважением
Матиас

Mrburnette
Вторник 17 ноября 2015 г., 17:11
Мадиас написал: <...>
Таким образом, чем больше кода (переменные) я вкладываю в него, тем больше мусора выходит, если я удаляю дополнительный код, шрифт становится правильным. Полностью расстраивает.
<...>
Матиас

Мадиас
Вт 17 ноября 2015 г., 17:18
Я использую RCT6 (и выбрал его), так что минимум 48 КБ (Victor использует этот чип с 64 КБ):
Sketch использует 141 844 байта (54%) пространства для хранения программы. Максимум составляет 262 144 байта.
Глобальные переменные используют 28 104 байта динамической памяти.

Мадиас
Вт 17 ноября 2015 г., 17:20
Хорошо, я определил большой массив как «const» (волнообразные данные, мне нужна скорость от SRAM, но это было легко попробовать):
Sketch использует 141 844 байта (54%) пространства для хранения программы. Максимум составляет 262 144 байта.
Глобальные переменные используют 11 720 байт динамической памяти.
Но тот же мусор на выставке. Я думаю, необходимо быть проблемой с указателем доступа к вспышке или что -то в этом роде.

Редактировать массивы шрифтов в Flash ("Extern Const fontdata XY")

Мадиас
Вторник 17 ноября 2015 г. 18:58
Хорошо, я думаю, что лучшее (и наиболее трудоемкое) решение - это объединить (лучше сокращать) моя библиотека ST8920 с Adafruit GFX One. Хорошая вещь в этом заключается в том, что мне не придется использовать несколько шрифтов (даже дважды), и все «графические функции» оставайтесь в пределах Adafruit GFX One. Следующие несколько часов, чтобы потратить....

Ахулл
Вторник 17 ноября 2015 г., 21:38
Искаженная дисплей звучит больше как проблема времени. Поскольку один либера. Я бы пошел с Adafruit Libs, добавить шрифты к ним, как правило, довольно просто.

Мадиас
Вт 17 ноября 2015 г., 22:36
Нет, не проблема времени, я установил все время задержки письма гораздо дольше. Странно то, что вся графика (коробки, строки) в порядке, без проблем, и вторичный дисплей (олинный библиотекой Adafruit) работает хорошо!
Должно быть действительно плохая вещь с «константом» и указателями для шрифтов (вся структура шрифта - это полностью указатель и «структура» безумие). Библиотека не идеальна, но неудача: я сделал полный графический интерфейс с этим куском S....без пост, включая создание собственных шрифтов и персонажей.
Я не могу использовать библиотеку Adafruit для этого дисплея (потому что их нет) . Единственная поддержка «Универсальной библиотеки» The ST7920 - это U8Glib, и я никогда не буду переносить этого монстра в STM32Duino, потому что он слишком большой и хочет поддержать все, поэтому вам нужны месяцы, чтобы адаптировать код. (Библиотека около 1 МБ!!).
Действительно плохая шутка в том, что я адаптировал многие библиотеки отображения с начала проекта STM32Duino для сообщества, и теперь я полностью терпеть неудачу со своим единственным.

Может быть, я немного объявляю структуру шрифта:
шрифты находятся в отдельном файле:
Пример: GLCD5X5_STM.CPP
В этом файле: #include "lcd7920_STM_RTOS.h" const uint8_t glcd5x5_STM[] = (...font data...)

Mrburnette
Вт 17 ноября 2015 г., 22:42
Мадиас написал: <...>
Действительно плохая шутка в том, что я адаптировал многие библиотеки отображения с начала проекта STM32Duino для сообщества, и теперь я полностью терпеть неудачу со своим единственным.
<...>

Мадиас
Вторник 17 ноября 2015 г., 11:00 вечера
Здесь, в Вене, находится в середине ночи :)
Но спасибо за предложение с бокалом вина, я пью 1/8 время от времени :)

Мадиас
Вторник 17 ноября 2015 г. 11:05
Кстати: «мусор» каждый раз один и тот же даже после сброса, так что не случайная вещь

Mrburnette
Вторник 17 ноября 2015 г. 11:35
Мадиас написал:Кстати: «мусор» каждый раз один и тот же даже после сброса, так что не случайная вещь

Ахулл
Ср 18 ноября 2015 г. 12:34
Хм в вашем примере вы начинаете с Font 5x5, затем

const extern lcdfont font5x9_stm;

5x9 тогда...

ЖК -дисплей.setFont (&font13x14_stm);

13x14.. Я в замешательстве, это 5x5, 5x9, 13x14... или я немного медленно поглощаю здесь?

Мадиас
Ср 18 ноября 2015 г. 11:01
Ахулл написал: Я в замешательстве, это 5x5, 5x9, 13x14... или я немного медленно поглощаю?

Мадиас
Ср 18 ноября 2015 г., 17:16
ХОРОШО!
Я только что реализовал adafruit gfx_as вместо использования оригинальных шрифтов драйверов (и даже графических функций).
Первый тест выглядит хорошо, но я только что протестировал минимальный код, поэтому я могу принести его в свой основной код и переписать графический интерфейс. Надеюсь, это сработает.
Основное преимущество: Помимо того, что мне не нужно использовать разные шрифты (для ST7920 и OLED), библиотека ST7920 есть; более или менее; Полностью совместимо со всеми другими библиотеками дисплея Adafruit (почти 99% по сравнению с SSD1306 из -за того же размера экрана) плюс преимущества двух отдельных буферов аппаратного экрана (чтобы я мог написать на один экран, в то время как другой отображается, как Два виртуальных экрана, но с преимуществом, которое встроено в аппаратном обеспечении, поэтому для переключения между ними необходима одна команда, а не все версии программного обеспечения, которые просто отправляют весь буфер на дисплей во время переключения). Я думаю, что это было лучшее решение, и это не было - удивительно - на самом деле нет боли, чтобы переоценить его!
Для сообщества я проверю новую библиотеку как смогу, и я помесчу ее в главное репо. (Я думаю, что я смогу немного оптимизировать метод «Drawpixel».

OV7670, Generic STM32F103RC и ILI9341 Дисплей