Интерфейс SPI замерзает в DMA ISR - [Решено] -

Стивестронг
Ср 28 декабря 2016 г. 11:08
Я публикую здесь как побочный вид этот пост.

Настройка:
SPI управляется DMA. DMA предоставляет 16 -битный поток данных от массива памяти в SPI, который просто выводит последовательные данные на PIN -код MOSI.
DMA настроен на создание прерывания после того, как он закончил, чтобы отправить все данные в SPI.

Поток:
DMA IRQ правильно генерируется после завершения передачи данных, но до того, как все 16 бит будут выпущены SPI.
Вот почему необходимо проверить статус SPI перед отправкой новых данных.

Проблема:
В DMA ISR, проверка флагов TXE и BSY интерфейса SPI с использованием этого кода не WOK: while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." /* and */ while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."

Ахулл
Чт 29 декабря 2016 г. 12:47
Терпеть меня, потому что я просто смотрю на документацию и понятия не имею (как обычно) о чем я говорю... но...
Я не вижу ничего явно не так с вашим кодом (так что вы, возможно, столкнулись с ошибкой)... но правда = 1 false = 0, что именно делает SPI_IS_BUSY return?! Нас одурачили, сравнив логический с int или чем -то глупым?

uint8 spi_is_busy (spi_dev * dev)
Определите, является ли устройство’S Периферийная занятость (SPI_SR_BSY) Флаг установлен.
Параметры:
девчонка -
Устройство SPI
Возвращаться:
Правда, IFF Dev’S BSY Flag установлен.


... Похоже, является действительным способом посмотреть, готовы ли вы сбросить следующую передачу. По крайней мере, так я читаю http: // docs.Leaflabs.com/static.Leaflab ... I/SPI.HTML
Я, наверное, лает не то дерево (или, возможно, даже не лая в правильном лесу). : D

Стивестронг
Чт 29 декабря 2016 г., 7:37 утра
Спасибо, Энди, но это было скопировано из рабочей части кода.
Я также попробовал ваше предложение, но, как и ожидалось, та же «ошибка», это что -то еще там.

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

Ахулл
Чт 29 декабря 2016 г., 9:17
Стивестронг написал:Спасибо, Энди, но это было скопировано из рабочей части кода.
Я также попробовал ваше предложение, но, как и ожидалось, та же «ошибка», это что -то еще там.

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

Стивестронг
Чт 29 декабря 2016 г., 9:44
Код обращается к SPI регистры внутри DMA ISR. ISR вводится, когда DMA закончит передавать все байты.

Это становится странным...Даже отключение периферийного SPI нарушает всю систему...
Вызов spi_peripheral_disable(_currentSetting->spi_d);

Стивестронг
Чт 29 декабря 2016 г., 9:54 утра
Просто для справки, я прикрепляю здесь свой код (грязный, полный линий отладки, но хорошо для тестирования) /*****************************************************************************/ void SPIClass::dmaSendIrq(void) { digitalWrite(DEB, LOW); //chan_regs->CCR &= (DMA_CCR_EN_BIT|DMA_CCR_TCIE)^0xFFFFFFFF; bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_TCIE_BIT, 0);//dma_disable_irq(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// //spi_tx_dma_disable(_currentSetting->spi_d); dmaIrqCount++; if ( dmaIrqCount>1 ) { digitalWrite(DEB, HIGH); digitalWrite(DEB, LOW); spi_peripheral_disable(_currentSetting->spi_d); // here we have the freeze, the CPU will not execute the following lines... digitalWrite(DEB, HIGH); digitalWrite(DEB, LOW); } digitalWrite(DEB, HIGH); while ( !spi_is_tx_empty(_currentSetting->spi_d) ); // "5. Wait until TXE=1 ..." digitalWrite(DEB, LOW); while ( spi_is_busy(_currentSetting->spi_d) ); // "... and then wait until BSY=0 before disabling the SPI." digitalWrite(DEB, HIGH); //uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! uint8 tail = bufTail; // check if there is buffer available to send if ( tail!=bufHead ) { // data to be written available? // write window address writeWinAddr( dmaBuffer[tail].winAddr ); // update length and memory to write from chan_regs->CMAR = (uint32)(&dmaBuffer[tail].color);//dma_set_mem_addr(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &dmaBuffer[bufTail].color);// chan_regs->CNDTR = dmaBuffer[tail].length;//dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, dmaBuffer[bufTail].length);// bufTail = (tail+1) & BUFF_SIZE_MASK; dmaSending = 1; writeCSActive(); // activate CS } else { //nothing to send dmaSending = 0; writeCSIdle(); // release chip select } digitalWrite(DEB, LOW); /**/ dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); if (dmaSending) { spi_tx_dma_enable(_currentSetting->spi_d); bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_TCIE_BIT, 1); // enable irq//dma_enable_irq(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1);//dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); // enable transmit } digitalWrite(DEB, HIGH); }

Rogerclark
Чт 29 декабря 2016 г., 10:20 утра
@stevestrong

Есть ли у вас синяя таблетка, вы можете превратиться в черный зонд, как если бы у кода было исключение, довольно легко узнать, что вызвало исключение (какая линия кода), используя GDB.

Стивестронг
Чт 29 декабря 2016 г. 10:26 утра
Роджер, если мне удастся отлаживать с Stlink, как именно я могу обнаружить Исключение причина?
Кодовая строка, вызывающая неприятности, на самом деле известна. На самом деле, любой доступ к регистре SPI, по -видимому, вызывает этот эффект.
Это должно быть связано с доступом в ISR, но я действительно не могу понять, что именно может так сильно беспокоить...

Пито
Чт 29 декабря 2016 г., 11:51
Для некоторых конфигураций отключение SPI и вход в режим остановки, пока продолжается передача может привести к повреждению текущего передачи, а/или флаг BSY может стать ненадежным.

Чтобы избежать любого из этих эффектов, рекомендуется уважать следующую процедуру при отключении SPI:
http: // stm32info.com/en/disabling-spi/

http: // электроника.Stackexchange.com/Qu ... y-flag-set

ZMEMW16
Чт 29 декабря 2016 г. 11:53 утра
возможно ли, что это 2 прерывания ?

Установите таймер (с глупым пределом), чтобы вынудить его только для отладка
висят настолько неопределенные : D

SRP

Стивестронг
Чт 29 декабря 2016 12:59
@pito
Спасибо, я хорошо знаю эту информацию, но никто из них не обсуждает System Hangup от SPI Register Accesses в DMA ISR! И именно это происходит в моем случае. Я не могу получить результат проверки флага BSY, система внезапно висит...

@zmemw16
Я не могу представить, почему DMA Trigger 2 должен прерываться одновременно.
Но, в любом случае, даже если это будет так, зачем замораживать систему, когда я получаю доступ любой регистр SPI В пределах ISR?

Какое серьезное исключение может произойти?
Если мне удастся отлаживать с Stlink, как именно я могу обнаружить причину исключения?

Ахулл
Чт 29 декабря 2016 г. 13:29
Не уверен, что это поможет, но вы можете посмотреть -> https: // github.com/leaflabs/libmaple/bl ... разрывы.текст
3.3: прерывания не обрабатываются Libmaple (ISRS.S)
~~~~~~~~~~~~ ~

Хотя Libmaple действительно предоставляет несколько обработчиков IRQ, он не определяет один
Для каждого доступного прерывания. Это верно по разным причинам: может быть
Периферийное или прерывание еще не поддерживается, может быть, нет
Полезное поведение по умолчанию и т. Д.

В этом случае было бы расточительно иметь отдельную функцию для
Каждое беззаботное прерывание. Чтобы справиться с этим, есть один файл, который
имеет дело со всем. Его название ISRS.S, и это живет
в том же каталоге, что и соответствующий Vector_Table.С. Для
Пример, для Maple, файл - libmaple/stm32f1/performance/isrs.С.

Это не сложно; Прочитайте источник, чтобы увидеть, как они работают.

4. Добавление собственных обработчиков прерываний
-------------------------------------

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

Рик Кимбалл
Чт 29 декабря 2016 г., 16:56
Стивестронг написал: Какое серьезное исключение может произойти?

Стивестронг
Чт 29 декабря 2016 г., 8:57 вечера
Я думаю, что решил проблему.

В случае ошибки я использовал следующую строку, чтобы подключить прерывание для DMA: dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, (void(*)())(&SPIClass::dmaSendIrq));

Rogerclark
Чт 29 декабря 2016 г., 21:33
@stevstrong

Я сам столкнулся с той же проблемой (но я помню, какой код я пытался написать) написать)

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

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

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