Трудно заставить SPI работать в режиме рабов

Кастотиу
Ср 15 ноября 2017 г. 14:55
Мне трудно заставить синюю таблетку работать в рабском режиме.

Я только что нашел два образца, которые используют два SPI в качестве ввода/ вывода на SD -карту, я пытаюсь изменить образцы, однако не могу заставить его работать на то, что мне нужно
https: // github.com/stevstrong/audio-sam ... C_HOST.Ино
Скачать/файл.PHP?ID = 623

Честно говоря, я не уверен, что мне нужно сделать, чтобы настроить SPI в режиме рабов.

В настоящее время у меня есть синяя таблетка, используя почти всю порту, отправляющую буфер памяти на дисплей RGB, что делает SPI (1) непригодным для использования, процессор тратит много времени на отправку буфера на дисплей RGB, поэтому у меня есть ESP8266, который делает Обработка изображений для смешивания нескольких изображений в одном, после того, как смешивание сделано, он отправляет кадр на STM32 для отображения.

У меня уже есть код в ESP8266, чтобы смешать изображения и отправляет кадр через SPI в STM (хорошо выглядит с логическим анализатором)

Теперь я хочу получить раму (около 6 кб) в порту 2 SPI на моем STM32, чтобы отображать на дисплее RGB.

Можете ли вы дать некоторые подсказки или упрощенный образец, как настроить мой порт SPI 2 для работы в режиме рабов, и получить обратный вызов или любой способ получить буфер, как только передается?

Спасибо.

Стивестронг
Ср 15 ноября 2017 г., 19:02
Вот простой пример, как настроить SPI 2 и соответствующий канал DMA RX 4: #include #include #include "libmaple/spi.h" ... /*****************************************************************************/ SPIClass SPI_2(2); /*****************************************************************************/ void SPI_setup(void) { // use SPI 2 for recording SPI_2.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); spi_rx_dma_enable(SPI_2.dev()); // enable SPI Rx DMA } /*****************************************************************************/ #define RECORDS_PER_BUFFER (6*1024) uint8_t data_buffer[RECORDS_PER_BUFFER]; /*****************************************************************************/ void DMA_Setup(void) { dma_init(DMA1); // init DMA clock domain // DMA setup transfer for SPI2 Rx dma_channel dma_ch = DMA_CH4; // SPI2 Rx DMA channel is channel 4, see reference manual 13.3.7. dma_disable(DMA1, dma_ch); // Disable the DMA tube. dma_setup_transfer(DMA1, dma_ch, &((SPI_2.dev())->regs->DR), DMA_SIZE_8BITS, data_buffer, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_HALF_TRNS | DMA_TRNS_CMPLT)); // flags dma_set_num_transfers(DMA1, dma_ch, RECORDS_PER_BUFFER); dma_set_priority(DMA1, dma_ch, DMA_PRIORITY_VERY_HIGH); dma_attach_interrupt(DMA1, dma_ch, DMA_Rx_irq); // attach an interrupt handler. dma_enable(DMA1, dma_ch); // Enable the DMA tube. It will now begin serving requests. } /*****************************************************************************/ // variables // set by HW when a complete DMA transfer was finished. volatile uint8_t dma_irq_full_complete; // set by HW when a DMA transfer is at its half. volatile uint8_t dma_irq_half_complete; /*****************************************************************************/ // This is our DMA interrupt handler. /*****************************************************************************/ void DMA_Rx_irq(void) { uint32_t dma_isr = dma_get_isr_bits(DMA1, DMA_CH4); if (dma_isr&DMA_ISR_HTIF1) { dma_irq_half_complete = 1; // signal for the main level } if (dma_isr&DMA_ISR_TCIF1) { dma_irq_full_complete = 1; // signal for the main level } dma_clear_isr_bits(DMA1, DMA_CH4); }

Кастотиу
Ср 15 ноября 2017 г., 20:24
Это круто, я постараюсь сообщить тебе.

Спасибо!!!

Кастотиу
Чт 16 ноября 2017 г. 1:21
Сегодня вечером я попробую этот код, однако где настройка SS в STM?

SPI на главном разговоре с SD -картой, а также с STM, поэтому автобус SPI занят разговором с разными рабами, я хочу убедиться, что канал DMA на STM32 собирает раму с автобуса только при SS (SS ( NSS2/PB12) низкий.

Как знает канал DMA? Я не вижу этого ни в одном из методов настройки.

Стивестронг
Чт 16 ноября 2017 г., 6:42
SS -штифт - это стандарт, выделенный для выбранного интерфейса SPI. Итак, для SPI 2 это PB12, для SPI 1 PA4.
В режиме рабов SPI будет только получение данных SS PIN активируется мастером, это способ работы по умолчанию.
DMA запускается только тогда, когда новые данные входят в SPI, так что это также автоматизируется аппаратным обеспечением.

Кастотиу
Чт 16 ноября 2017 г., 7:36 утра
Я не знаю, чего мне не хватает, я не могу сделать IRQ, чтобы запустить.

Проверил SPI2
PB12 -> CS
PB13 -> CLK
PB14 -> Мисо
PB15 -> Моси

У меня есть осциллограф и анализатор в автобусе, и все выглядит нормально, я упростил мастер -код только для того, чтобы отправить в повторение 32 байт с контентом "Hello Thing".

Даже на STM32 я скопировал метод void regs_info (void) из образцов и сбрасываю содержание каждую секунду, и я получаю то же самое:
DMA1.ISR: 0
DMA1.CCR2: 0
DMA1.CNDTR2: 0
SPI2.CR1: 440
SPI2.CR2: 0
SPI2.SR: 43

Прерывание никогда не запускается, что еще я могу проверить?
Spibus.png
Spibus.PNG (101.75 киб) просмотрено 867 раз

Стивестронг
Чт 16 ноября 2017 г. 11:37
Ваш контролируемый канал DMA был неверным, это должен быть канал 4, регистрирует CCR4 и CNDTR4.

Но в любом случае, я нашел очень важный шаг, отсутствующий в потоке настройки, это включение SPI RX DMA.
Это должно быть сделано путем вставки дополнительной строки в настройку SPI:
#include "libmaple/spi.h" ... void SPI_setup(void) { // use SPI 2 for recording SPI_2.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); spi_rx_dma_enable(SPI_2.dev()); // enable SPI Rx DMA }

Кастотиу
Чт 16 ноября 2017 г. 13:06
Оно работает !!!

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

Еще один вопрос, как обрабатываются ошибки передачи?

Например, я ожидаю, что 6144 (6x1024) байтов, однако, если по какой -то причине не все байты появятся, буфер не будет полностью заполнен, а основной цикл не обнаружит весь буфер, SS будет высоким, а IRQ не будет инициировано.

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

Если продолжить, где он остался в предыдущем кадре, то потерь одного байта может вызвать массивную цепную реакцию беспорядка в буфере.

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

Стивестронг
Чт 16 ноября 2017 г. 13:15
Вы можете отслеживать RGISTERS SPI и DMA на предмет ошибок, и если это произойдет, то повторно введите DMA.

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

Кастотиу
Чт 16 ноября 2017 г. 13:31
Могу ли я прикрепить прерывание к падающему краю штифта SS?

На мастере я мог бы дать несколько микросекунд в качестве буфера временного времени после того, как SS снизился и начал передавать данные, этого времени должно быть достаточно, чтобы рабы приколоть.

Стивестронг
Чт 16 ноября 2017 г. 13:44
Я не уверен, но вы можете попытаться увидеть, работает ли это.
Если нет, то подключите тот же провод к другому штифту.

Кастотиу
Чт 16 ноября 2017 г. 14:35
Да, подключение к другому PIN -кону тоже может работать, так как моя проблема заключалась в том, что ESP8266 легко заканчивается булавками, однако все еще осталось на STM.

Я почти там, я установил код на Мастере и Раве, и он работает как мастер мечты, отправляющий рамы и рабыня, потребляя их в режиме реального времени, однако я не могу получить более 35 МГц.

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

В настоящее время я использую RGB с двойным буфером, поэтому мне не нужен другой буфер, я хочу, чтобы канал DMA писал на заднем плане RGB, как только рама получен, я просто хочу поменять задний буфер на передний буфер На дисплее, поэтому операция немедленная, а «новый» задний буфер готов к заполнению DMA.

Я еще не пробовал, однако на функции IRQ мне нужно сделать что -то вроде:
void DMA_Rx_irq(void) { uint32_t dma_isr = dma_get_isr_bits(DMA1, DMA_CH4); if (dma_isr & DMA_ISR_TCIF1) { matrix.swapBuffer(); byte* backBuffer = matrix.backBuffer(); dma_setup_transfer(DMA1, dma_ch, &((spi2.dev())->regs->DR), DMA_SIZE_8BITS, backBuffer, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_HALF_TRNS | DMA_TRNS_CMPLT)); // flags } dma_clear_isr_bits(DMA1, DMA_CH4); }

Стивестронг
Чт 16 ноября 2017 г. 8:10 вечера
Вам нужно сделать некоторую обработку по полученным данным?
Если нет, то вы можете использовать один и тот же двойной буфер для получения данных непосредственно в буфере RGB.
Сделайте круговой круг DMA (который на самом деле имеет место в моем примере) и установите его в буфер RGB и забудьте обо всем.
Нет необходимости повторно вводить DMA, если ничего не изменится, он будет постоянно писать двойные буферы с самого начала, когда он заканчивается (поэтому «круговой»).

Кастотиу
Чт 16 ноября 2017 г., 21:46
У меня нет обработки на рабу, однако мне нужно позвонить в матрицу.Swapbuffer () Каждый раз, когда была получена полная кадра, чтобы сообщить дисплею, чтобы переключатель использовал задних бензин.

Я думаю, я получил то, что ты говоришь.

Новые шаги:
Выделите один последовательный кадрский буфер * 2, чтобы удерживать две кадры 6144 * 2 (в настоящее время у меня есть два различных буфера 6144)

На матрице буферы будут
Byte VideoBuffer [12288];
*Frontbuffer = VideoBuffer;
*Backbuffer = VideoBuffer + 6144

На функции настройки DMA я должен предоставить указатель на видеобаллер, и я должен сказать, что у меня есть 2 записи 6144 вместо 1 вместо 1.
Тогда я называю матрицу.Swapbuffer () Когда IRQ запускается как для половины, так и для полного, DMA заполнит две кадры, прежде чем автоматически сбрасываться, так как это круглое.

Я думаю, что будет работать отлично, я подумал, что DMA всегда заполняет посредник, который не отображается на экране, и для каждого полного заполненного буфера вызовите Swapbuffer (), однако это потребовало бы для перемещения PTR, где DMA необходимо писать после каждого кадра. , решение, которое вы предлагаете, звучит намного проще, только предостережение заключается в том, что мне нужно выделить 2 видео буфера в качестве единого последовательного буфера, STM32 имеет 20 тыс., И мне нужно взять 12 тыс., Поэтому, вероятно, мне придется выделить этот буфер, как только Код начинает избегать фрагментации памяти и заканчивается память.

Также намеренно для тестирования в середине мастер -потоковой передачи я пропустил один байт из кадра, и он создал массивную проблему цепной реакции в рабе, и дисплей сильно компенсируется с течением времени, поэтому мне определенно придется реализовать решение для восстановления IRQ, когда SS снижается, чтобы проверить здоровье буфера DMA или аналогичное решение, иначе какой -то шум в автобусе вызвал бы довольно плохое поведение.

Кастотиу
Сб 18 ноября 2017 г. 1:54
Приведенные выше шаги отлично работают, и все работает, как и ожидалось, у меня включен двойной буфер, низкая площадь памяти, а дисплей RGB освежает при 250 Гц 1288W32H12BPP, должен был сделать несколько хитростей на матрице RGB, чтобы обмениваться буферами в зависимости от того, если DMA заполнит DMA. Первая или вторая половина видеобаффера (Swapbuffer () в классе RGBMatrix не детерминирован), мастер посылает кадры, и раб обрабатывает их, в основном я закончил с ним.

Теперь следующий шаг - получить несколько ответов от раба.

Например, STM имеет RTC, я хочу получать текущее время/данные каждый раз, когда мастер сбрасывает.

Они, как я понимаю, Master всегда генерирует тактовые циклы, поэтому я добавил 2 дополнительных байта в начале каждого кадра, отправленного мастером, чтобы предоставить подпись о том, что отправляет мастер.

Если раб получает подпись, такую ​​как «df» (дисплей), то раб возьмите Dmabuffer и отображает данные на дисплее RGB.

Также теперь я отправляю, когда необходим полный кадр с фиктивными данными, но с подписью «tr» (запрос времени), однако я не могу понять, как отправить ответ обратно в мастер.

Кроме того.

Что я пытаюсь
Spiclass spi2 (2);
Я попробовал SPI2.Отправить, SPI.dmasend, spi.Напишите, однако, кажется, ничто не помещает ответ на мисо, очевидно, мне не хватает шагов или всей картинки.

Каковы шаги для раба, чтобы отправить ответ обратно Мастеру?

Стивестронг
Сб 18 ноября 2017 г. 10:59 утра
Если вам действительно нужно передавать из раба только пару байтов, то вы могли бы использовать USART (сериал), у синей таблетки есть 3 USARTS.

В противном случае, чтобы передавать через SPI раб, вам нужно сделать следующее:
- Настройка канала DMA TX для количества байтов, которые вы хотите передать:
static const dma_channel dma_tx_ch = DMA_CH5; // SPI2 Tx DMA channel is channel 5, see reference manual 13.3.7. uint8_t dma_tx_buffer[8]; // set the correct size /*****************************************************************************/ void DMA_Tx_Setup(void) { dma_init(DMA1); // init DMA clock domain // DMA channel configuration for SPI2 Tx dma_disable(DMA1, dma_tx_ch); // Disable the DMA channel. dma_setup_transfer(DMA1, dma_tx_ch, &((SPI_2.dev())->regs->DR), DMA_SIZE_8BITS, data_tx_buffer, DMA_SIZE_8BITS, (DMA_MINC_MODE)); // flags dma_set_num_transfers(DMA1, dma_tx_ch, sizeof(data_tx_buffer)); dma_set_priority(DMA1, dma_tx_ch, DMA_PRIORITY_HIGH); dma_enable(DMA1, dma_tx_ch); // Enable the DMA channel. It will now begin serving requests. }

Кастотиу
Солнце 19 ноября 2017 г. 8:17 утра
Отлично, я попробую сегодня.

Я работаю с разгоном в 128 МГц, так как мне нужно было получить хорошую частоту обновления для матрицы RGB и программирования с помощью ST-Link V2, поэтому я использую USART1 для отладки, USART2 используется матрицей RGB, а также PB10 (USART3) USART2 используется RGB, также PB10 (USART3), USART2 используется RGB, также PB10 (USART3) USART2, также PB10 (USART3) USART2 используется USART2, а также PB10 (USART3) используется USART2 (USART3) USART2 используется USART2 (USART3) USART2 используется USART2 (USART3). используется OE матрицы, однако я могу переместить этот PIN -код, если необходимо.

Я сделаю снимок с SPI, иначе имеет смысл использовать USART3, это всего лишь несколько байтов, которые раб должен отправить.

Кастотиу
Сб 02 декабря 2017 г. 8:18 утра
Я некоторое время не отвечал, так как не мог заставить раба отправить что -нибудь в автобус, поэтому я перешел на что -то еще, однако я закончил другие модули, и теперь я вернулся, где остановился, чтобы дать новую попытку.

Я настраиваю канал DMA в качестве образца ниже, однако единственное, что я получаю на автобусе, - это активность MOSI, и вообще нет мисо.

Есть ли что -то еще, что я могу проверить?

У меня были идеи, я публикую урок здесь, чтобы увидеть, сможете ли вы что -то заметить:
#include "EspSlave.h" #include "RGBMultiMatrix.h" #include "Buzzer.h" #include static EspSlave *activeSlave = NULL; EspSlave::EspSlave() : ss_pin(SPI2_NSS_PIN), spi2(2) { activeSlave = this; } void EspSlave::init(uint8* videoBuffer, uint16 videoBufferSize) { Srl.println("Buffer Size"); dmaBuffer = videoBuffer; dmaBufferSize = videoBufferSize; pinMode(ss_pin, OUTPUT); digitalWrite(ss_pin, HIGH); spi2.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); spi_rx_dma_enable(spi2.dev()); spi_tx_dma_enable(spi2.dev()); bb_peri_set_bit(&((spi2.dev())->regs->CR1), SPI_CR1_RXONLY_BIT, 0); // make it full duplex dmaInit(); dmaSetup(); } void EspSlave::dmaInit(void) { dma_irq_full_complete = 0; dma_irq_half_complete = 0; dma_clear_isr_bits(DMA1, DMA_CH4); dma_clear_isr_bits(DMA1, DMA_CH5); Srl.println("Dma init"); } void EspSlave::dmaBufferReady(bool fullBuffer) { if (fullBuffer) { dma_irq_full_complete = 1; } else { dma_irq_half_complete = 1; } } void DMA_Tx_irq(void) { //uint32_t dma_isr = dma_get_isr_bits(DMA1, DMA_CH5); Srl.print("t"); //dma_clear_isr_bits(DMA1, DMA_CH5); } void DMA_Rx_irq(void) { uint32 dma_isr = dma_get_isr_bits(DMA1, DMA_CH4); if (dma_isr & DMA_ISR_HTIF1) { activeSlave->dmaBufferReady(false); } if (dma_isr & DMA_ISR_TCIF1) { activeSlave->dmaBufferReady(true); } dma_clear_isr_bits(DMA1, DMA_CH4); } static const dma_channel dma_tx_ch = DMA_CH5; // SPI2 Tx DMA channel is channel 5, see reference manual 13.3.7. uint8 data_tx_buffer[8]; // set the correct size void EspSlave::dmaSetup(void) { data_tx_buffer[0] = 255; data_tx_buffer[1] = 200; data_tx_buffer[2] = 170; data_tx_buffer[3] = 130; data_tx_buffer[4] = 100; data_tx_buffer[5] = 70; data_tx_buffer[6] = 30; data_tx_buffer[7] = 1; Srl.println("Dma setup starts"); dma_channel dma_ch = DMA_CH4; // SPI2 Rx DMA channel is channel 4, see reference manual 13.3.7. dma_init(DMA1); // init DMA clock domain, DMA setup transfer for SPI2 Rx dma_disable(DMA1, dma_ch); // Disable the DMA tube. dma_disable(DMA1, dma_tx_ch); dma_setup_transfer(DMA1, dma_ch, &((spi2.dev())->regs->DR), DMA_SIZE_8BITS, dmaBuffer, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_HALF_TRNS | DMA_TRNS_CMPLT)); // flags dma_setup_transfer(DMA1, dma_tx_ch, &((spi2.dev())->regs->DR), DMA_SIZE_8BITS, data_tx_buffer, DMA_SIZE_8BITS, (DMA_MINC_MODE)); // flags dma_set_num_transfers(DMA1, dma_ch, dmaBufferSize); dma_set_num_transfers(DMA1, dma_tx_ch, sizeof(data_tx_buffer)); dma_set_priority(DMA1, dma_ch, DMA_PRIORITY_VERY_HIGH); dma_set_priority(DMA1, dma_tx_ch, DMA_PRIORITY_HIGH); dma_attach_interrupt(DMA1, dma_ch, DMA_Rx_irq); // attach an interrupt handler. dma_attach_interrupt(DMA1, dma_tx_ch, DMA_Tx_irq); // attach an interrupt handler. dma_enable(DMA1, dma_ch); // Enable the DMA tube. It will now begin serving requests. dma_enable(DMA1, dma_tx_ch); // Enable the DMA tube. It will now begin serving requests. Srl.println("Dma setup ends"); } void EspSlave::processDmaBuffer(uint8* buffer, bool isCompletedBuffer) { // First two bytes are master instruction switch (buffer[0]) { case MASTER_INSTRUCTION_DISPLAY: { swapDmaBuffer(buffer, isCompletedBuffer, false); return; } case MASTER_INSTRUCTION_BUZZER: { //Srl.println("Instruction Buzzer"); byte command = buffer[1]; switch (buffer[1]) { case MASTER_INSTRUCTION_BUZZER_VOLUME: { buzzer.setVolume(buffer[2]); break; } case MASTER_INSTRUCTION_BUZZER_FRECUENCY: { uint16 frecuency = buffer[2] << 8 | buffer[3]; buzzer.setFrecuency(frecuency); break; } default: { Srl.println("Buzzer Unknown"); break; } } break; } case MASTER_INSTRUCTION_GET_TIME: { Srl.print("TIME REQUESTED:"); //byte d1[2]; //d1[0] = 'A'; //d1[1] = 'A'; //if (buffer[1] == 0) //{ // spi2.write(d1, 2); // Srl.println("INSTRUCTION"); //} //if (buffer[1] == 1) //{ // spi2.send(d1, 2); // Srl.println("RESPONSE"); //} break; } default: { Srl.println(buffer[0]); Srl.println(buffer[1]); Srl.println("Unknown Frame"); } } swapDmaBuffer(buffer, isCompletedBuffer, true); } void EspSlave::swapDmaBuffer(uint8* buffer, bool isCompletedBuffer, bool isInstruction) { if (isCompletedBuffer == false) { if (isInstruction) { memcpy(buffer, dmaBuffer + VIDEO_FRAME_INSTRUCTION_SIZE, 12); } matrix.activateBuffer(0); } else { if (isInstruction) { memcpy(buffer, dmaBuffer, 12); } matrix.activateBuffer(1); } } void EspSlave::loop() { if (dma_irq_half_complete) { dma_irq_half_complete = 0; processDmaBuffer(dmaBuffer, false); } if (dma_irq_full_complete) { dma_irq_full_complete = 0; processDmaBuffer(dmaBuffer + VIDEO_FRAME_INSTRUCTION_SIZE, true); } } EspSlave spiSlave;

Стивестронг
Сб 02 декабря 2017 г. 10:19
Вы читали это ViewTopic.PHP?F = 38&T = 2818&P = 37820#P37814 ?

Кастотиу
Вт 05 декабря 2017 г. 11:59
Я попытался, чтобы 8 часов сделала код в ссылке выше (не-DMA) для работы без успеха. Отправить данные о мисо было легким, однако было болезненным и совершенно ненадежным, я использовал каждую комбинацию, пока ( !(Регс->Старший & Spi_sr_txe)); в то время как ((регс->Старший & Spi_sr_bsy)));, включить/отключить прерывания и т. Д., Однако отправка данных была вне синхронизации, иногда один и тот же символ был отправлен несколько раз, а также я получил большой удар по производительности, где версия DMA работала на 42 МГц, не -DMA с только RX был стабильным при 24 МГц и только 14 МГц в режиме RX/TX.

Итак, 99.999% случаев, когда мастер использовал часы 24 МГц и уменьшается до 14 МГц, когда это необходимо, данные из раба, однако даже замедляясь до 1 МГц, которые вернулись, были ненадежными.

Пробовал практически почти все.

Отказался от всех изменений и снова начался с DMA, и, наконец, я сделал полномудуплексную установку DMA, работающую на 42 МГц, а также я удаляю круглый буфер и изменяю, чтобы синхронизировать указатель DMA к SS Low (по крайней мере, что это Я хочу сделать), таким образом, мой rgbmatrix будет невосприимчив к шуму на часах, одно такточное смещение цикла может привести к невозможности повреждения каскадных данных на дисплее, так как буфер DMA не будет писать данные в буфере как Мастер ожидает этого, если я синхронизирую указатель DMA с SS Low, проблема должна исчезнуть.

Здесь почти нет информации о том, чтобы заставить STM32 работать с DMA в полном дуплексе, я опубликую свою настройку, как только закончу чистить код.

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

Рабочие флаги для DMA Full Duplex
uint32 flags = ((_currentsetting->bitorder == msbfirst ? Spi_frame_msb: spi_frame_lsb) | Spi_dff_8_bit | Spi_bidioe);

Кастотиу
Чт, 07 декабря 2017 г. 8:52 утра
Стив, спасибо за всю вашу помощь, а также все остальные тоже.

У меня есть SPI DMA Full Duplex, работающий мечтой. Я не использую круглый буфер, и на самом деле я даже не использую IRQ из DMA.
Проблема с «обычной» настройкой заключается в том, что DMA запустит IRQ, когда буфер наполовину/полный, однако это не очень детерминированно, поскольку он может вызвать буфер, который полон шума и выйти из синхронизации с мастером и испорченным данные.

Я приложил прерывание к падению/восхождению SPI CS.
Во время падения я повторно включает DMA RX и TX, это также перезагружает указатель TX/RX DMA; Поскольку флаг круглого буфера не установлен, DMA автоматически отключается после каждого полного буфера.
Во время подъема I обработать буфер DMA RX, как есть, не ожидая полного буфера RX.

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

Однако есть небольшая предостережение, поскольку запуск IRQ и перезапуск DMA может занять некоторое время, мастер должен обеспечить небольшое время простоя во время перехода на CS на низкий или раб может потерять первый байт. Если я не предоставлю задержки, я потеряю первый байт примерно за 1% запросов.
Доказано, что предоставление простоя около 50 мкм было более чем достаточно, чтобы захватить 100% запроса.

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

Скоро я опубликую свою настройку для того, кто должен сделать что -то подобное в будущем.

Еще раз спасибо за помощь, также потому, что я не использую Double Buffer для буфера DMA, я уменьшил 1028 в размере оперативной памяти, и все находится под контролем с общей суммой около 16300 байтов, что дает мне около 4 тыс. ОЗУ, чтобы играть в время выполнения.

Кстати, я обнаружил, почему серийная загрузка бинана была на 1 км меньше, чем бинар STLINK, в плате.TXT Serial имеет опцию -deserial_usb " :), В любом случае, это было бы как последний вариант, так как отсутствие сериала довольно плохо, поскольку все мои отладка полагаются на это, потребление потока оперативной памяти было больше о том, чтобы «иметь» и «знание» ограничений чипа, чем что -либо еще.

Стивестронг
Чт, 07 декабря 2017 г. 9:01
Я бы сделал повторную реинтиализацию DMA после обработки данных, при росту прерывания края.
Таким образом, на падении (начало передачи SPI) у вас будет уже подготовлен DMA, поэтому время ожидания не требуется, и байты не будут потеряны.

Кастотиу
Чт, 07 декабря 2017 г. 9:05 утра
Правда, это потрясающе и должно работать : D

Сначала я только прикреплялся к падению и позволил буфере DMA заполнить, чтобы отправить мне IRQ, так как был круговой буфер, никогда не приходил мне в голову, чтобы изменить код для повторного входа при подъеме после изменения моего кода, чтобы прикрепить к падению/росту

Я попробую сейчас!!

Кастотиу
Чт, 07 декабря 2017 г. 9:33 утра
Оно работает!!!, Сокращение моих запросов с 300 мкл до 250 мкм, и на самом деле потому, что теперь я делаю обе вещи (Re-Init/Bark DMA Buffer «Готовы к обработке») при подъеме, мне не нужно прикреплять CS IRQ для изменений, но просто просто к повышению, что позволяет мне удалить все следующие коды
uint16 ss_bit = PIN_MAP[SLAVE_NSS_PIN].gpio_bit; volatile uint32* ss_port = portInputRegister(digitalPinToPort(SLAVE_NSS_PIN)); // Read the SS state bool ss_rising = *ss_port & (1 << ss_bit); if (ss_rising) {} else {}

Кастотиу
Чт, 07 декабря 2017 г. 12:58
Теперь, когда все на установке DMA, я хочу начать работать с данными, отправленными рабом в мастере, однако у меня проблема, а не нарушитель сделок, но у меня проблема с первым байтом Мисо, это кажется «ненадежным».

Содержание txbuffer устанавливается должным образом во время ответа (фиксированный массив из 10 элементов, предварительно выделяемых во время запуска), однако, как первый байт, отправленный мисо, является «добрым» из последнего байта, отправленного из предыдущего ответа TX, потому что я мог Не объясняйте, что происходит, тогда во время DMA Reinit я также сбросил TXBUFFER "MEMSET (TXBUFFER, 0, TXBUFFERISIZE)"

Тогда я вижу, что даже если установить txbuffer [0] = что -то, не получайте этого байта в мисо в текущем ответе, но в следующем.

Так что в настоящее время я сделал просто игнорировать первый байт и не используйте его в ответе, однако в конце концов я хотел бы знать, что происходит.

Я не могу это объяснить, однако, как будто контроллер DMA не делает то, что должен делать для первого байта.

Как вы можете видеть в приложении в качестве трудоустройства, теперь я всегда оставляю первый байт Unset и отправляю команду ответа («Ответ времени») в этом случае в следующих байтах.

Вы когда -нибудь видели что -то подобное на SPI Miso?

Стивестронг
Чт, 07 декабря 2017 г. 15:01
Не увидев вашего кода, я могу только предложить
- Отключить DMA,
- Прочитайте регистр данных SPI
- Настройка и включение следующей передачи DMA.

Отправленные данные должны быть действительными, прежде чем сделать последний шаг, потому что DMA доставит первый байт для передачи в SPI, когда SPI включен (запускается флагом TXE).