Nucleo F401RE - Попытка заставить i2s и DMA работать

Винсентп
Чт, 07 июня 2018 г., 7:30 утра
Привет !
Как опубликовано в «Приветственной ветке», Arm Noob здесь, наша лаборатория мигрирует с 15 -летнего Dev с Microchip 8 и 16 -битным MCU на Arm MCU.
Мы используем Duino STM32, чтобы обучать что -то, что началось как «простой» проект, но мы в тупике.

Нам нужно работать с I2S и DMA, чтобы генерировать сигналы. Мы следили за правильной кривой обучения о конфигурации ввода / вывода, настройках часов и т. Д., И даже получили I2S для работы в режиме опроса, и мы могли бы вывести образцы, поэтому SPI2 / I2S правильно настроен

Теперь мы добавляем DMA, а доска замерзает. Рад опубликовать наш код старта и попытаться получить некоторую помощь в этом месте, где мы читали довольно довольно довольно и многому научились (ура).

Код до сих пор очень прост, но у меня нет отладчика, чтобы проверить, что происходит. Основная петля отражает состояние переключателя в бортовое светодиод, чтобы проверить, что он все еще работает.
Когда мы запускаем DMA для первой транзакции I2S, количество выборок решилось, что на самом деле выходит (мастер -часы, часы слова и образцы), затем оно замерзает, а основной цикл не отзывчивый.

Я предполагаю, что IRQ запускается в конце транзакции DMA, но идет либо в ловушку, либо в никогда не. Я переопределяю слабые ручки IRQ и обратные вызовы i2s, но пока я не думаю, что попадаю в них.

Вот наш код. Единственный мод, который мы внесли для инструментального оборудования STM32 Arduino, - это включить I2S (и DMA, я думаю) в основной конфигурации .H файл, в котором вы определяете, с чем компилировать, а что нет
Мы еще не используем кодек, мы только информировали объект, но его можно избежать для тестирования. Это должно работать на обнаженном нуклео

любая идея ?
Спасибо
#include #include #include #include #include "stm32f4xx_hal_gpio.h" #include #include "stm32f4xx.h" #include ////////////// VARIABLES DECLARATION //////////////////////// #if !defined (HSI_VALUE) #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ #endif /* HSI_VALUE */ // A full cycle, 16-bit, 2's complement Sine wave lookup table uint16_t sine_table[256] = { 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3, 0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894, 0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc, 0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c, 0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c, 0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22, 0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5, 0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc, }; // I2S init stuctures __I2S_HandleTypeDef hi2s2; // DMA init & structure DMA_InitTypeDef DMA_InitStruct; DMA_HandleTypeDef hdma1; // SGTL5000 I2C control AudioControlSGTL5000 MyCodec; int i = 0; uint16_t datasize = 4; uint16_t AudioSampleLR[12]; typedef enum LeftOrRight {LEFT_CHANNEL = 0, RIGHT_CHANNEL}; bool FlagSendNewSample = false; uint16_t SampleCounter = 0; uint32_t transmitdelay = 1000; uint32_t RunningTime = 0; HAL_StatusTypeDef msg; int led = 13; int user_switch = 23; // PC13 = Digital Pin 23 /////////// END OF DECLARATION ///////////////////////////////////////////// static void MX_I2S2_Init(void) { // -@- Make sure that either: // (+@) I2S PLL is configured or // (+@) External clock source is configured after setting correctly // the define constant EXTERNAL_CLOCK_VALUE in the stm32f4xx_hal_conf.h file. hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_TX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_48K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { Serial.println("erreur I2S init"); } } // (#) Initialize the I2S low level resources by implement the HAL_I2S_MspInit() API: // I/O mapping init for I2S void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) { Serial.println("MspInit ici!!!"); // (##) I2S pins configuration: // (+++) Enable the clock for the I2S GPIOs // INSTRUCTIONS FROM THE FILE stm32f4xx_gpio.c /* (#) Enable the GPIO AHB clock using the following function: __HAL_RCC_GPIOx_CLK_ENABLE(). (#) Configure the GPIO pin(s) using HAL_GPIO_Init(). (++) Configure the IO mode using "Mode" member from GPIO_InitTypeDef structure (++) Activate Pull-up, Pull-down resistor using "Pull" member from GPIO_InitTypeDef structure. (++) In case of Output or alternate function mode selection: the speed is configured through "Speed" member from GPIO_InitTypeDef structure. (++) In alternate mode is selection, the alternate function connected to the IO is configured through "Alternate" member from GPIO_InitTypeDef structure. */ // Beware, Clock enable has to be set for both port B and C (!) __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); // (+++) Configure these I2S pins as alternate function pull-up. GPIO_InitTypeDef GPIO_InitStruct; if(hi2s->Instance==SPI2) { /* Peripheral clock enable */ __HAL_RCC_SPI2_CLK_ENABLE(); /**I2S2 GPIO Configuration PB12 ------> I2S2_WS PB13 ------> I2S2_CK PB14 ------> I2S2_ext_SD PB15 ------> I2S2_SD PC6 ------> I2S2_MCK */ // Word Clock, Bit Clock, Data (MOSI) GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_15 ; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // Master Clock GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // External SD (full duplex, incoming I2S) GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // DMA stuff __HAL_RCC_DMA1_CLK_ENABLE(); // DMA1_Stream4_IRQn interrupt configuration // AN4031 ST : table of DMA instance (controller #) vs channel vs peripheral // SPI2 TX (used for I2S) is DMA Controller #1 (out of 2) stream 4 channel 0 hdma1.Instance = DMA1_Stream4; hdma1.Init.Channel = DMA_CHANNEL_0; hdma1.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma1.Init.PeriphInc = DMA_PINC_DISABLE; hdma1.Init.MemInc = DMA_MINC_ENABLE; //hdma1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; //hdma1.Init.MemDataAlignment = DMA_PDATAALIGN_WORD; hdma1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma1.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma1.Init.MemBurst = DMA_MBURST_SINGLE; hdma1.Init.PeriphBurst = DMA_PBURST_SINGLE; hdma1.Init.Mode = DMA_NORMAL; hdma1.Init.Priority = DMA_PRIORITY_LOW; hdma1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma1) != HAL_OK) Serial.println("DMA init Error"); __HAL_LINKDMA(&hi2s2,hdmatx,hdma1); HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 2, 0); HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); __HAL_DMA_ENABLE(&hdma1); } //Serial.println("MspInit fini..."); } void DMA1_Stream4_IRQHandler(void) { digitalWrite(led, HIGH); HAL_DMA_IRQHandler(hi2s2.hdmatx); } void SPI2_IRQHandler(void) { digitalWrite(led, HIGH); } void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { //Serial.print("#"); digitalWrite(led, HIGH); } void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) { Serial.print("."); digitalWrite(led, HIGH); if(SampleCounter<256) { AudioSampleLR[LEFT_CHANNEL] = sine_table[SampleCounter]; //AudioSampleLR[RIGHT_CHANNEL] = sine_table[SampleCounter]; AudioSampleLR[RIGHT_CHANNEL] = 0; SampleCounter++; FlagSendNewSample = true; } else SampleCounter = 0; HAL_I2S_Transmit_DMA(&hi2s2, AudioSampleLR, 1); } void setup() { Serial.begin(115200); delay(100); Serial.println("HAL_Init()..."); HAL_Init(); pinMode(led, OUTPUT); pinMode(user_switch, INPUT); // Fills up the I2S handle structure with the I2S configuration (mode, SR etc) // (#) Program the Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity // using HAL_I2S_Init() function. // note that there's no direct call to HAL_I2S_MspInit() as we override it locally and it takes over the weak // prototype defined in HAL. It's called within HAL_I2S_Init() MX_I2S2_Init(); // PLL & Clock Setup for the I2S module // With a 48k Sample rate, I2S modules creates a master clock => FC = FS * 256 (or 12.288 MHz with FS = 48k) RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S; // with HSI, leads to 48.08 KHz Word clock - adjust +/- 1 for fine tuning or use crystal (HSE) PeriphClkInitStruct.PLLI2S.PLLI2SN = 195; //PeriphClkInitStruct.PLLI2S.PLLI2SN = 390; PeriphClkInitStruct.PLLI2S.PLLI2SR = 1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Serial.println("erreur config horloge periph I2S ..."); } //Wire.begin(); //delay(5); //Wire.setClock(10000); AudioSampleLR[LEFT_CHANNEL] = AudioSampleLR[RIGHT_CHANNEL] = 0xAA55; SampleCounter = 0; FlagSendNewSample = false; // HAL_I2S_DMAResume(&hi2s2); HAL_I2S_Transmit_DMA(&hi2s2, AudioSampleLR, 1); //__HAL_I2S_ENABLE_IT(&hi2s2,I2S_IT_TXE); digitalWrite(led, HIGH); //MyCodec.setAddress(LOW); // SGTL5000 Codec start // This will also launch Wire.begin() and will initialize the codec with default values //MyCodec.enable(); //MyCodec.volume(0.5, 0.5); /* Wire.beginTransmission(0x0A); Wire.write(0); Wire.write(0); if(Wire.endTransmission(false) != 0) { Serial.println("Wire write error"); } if (Wire.requestFrom((int)0x0A, 2) < 2) { Serial.println("Wire read error"); } unsigned int val = Wire.read() << 8; val |= Wire.read(); Serial.println(val); */ RunningTime = micros(); } void loop() { if(digitalRead(user_switch)) digitalWrite(led, HIGH); else digitalWrite(led, LOW); }

Chismicro
Чт, 07 июня 2018 г., 19:31
Может быть, общая структура просто работает из коробки для этого MCU. Я не уверен, но есть и различные филиалы, которые еще больше продвинулись:
Пример i2s
Буферы DMA включены.

fpistm
Чт, 07 июня 2018 г., 8:29 вечера
Эскиз - это CPP, поэтому вам нужно использовать extern "C"

Винсентп
Пт. 08 июня 2018 г. 13:06
Большое спасибо вам обоим, я совершенно уверен, что Extern C объясняет, почему мои обратные вызовы не составлены, что создает плохую поездку, когда Quick in IRQ.
Буду продолжать делать мои домашние работы и сообщить вам о результатах !

ваше здоровье

Винсентп
Пн 11 июня 2018 г. 15:25
Итак, я пробовал обратные вызовы Extern C без результатов (доска все еще замораживает после отправки первого массива DMA).

Я также установил общее ядро ​​и собрал пример, но пример Sawtooth ничего не дает абсолюции, попробовал SPI3 и SPI2.

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

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

Является ли общий ядро ​​+ I2S LIB был протестирован на плате F401 Re Nucleo ?

Спасибо

fpistm
Пн 11 июня 2018 г. 18:14
Какое ядро ​​вы использовали?
STM32Generic или STM Core?

Винсентп
Вт 12 июня 2018 г. 15:04
[fpistm - Пн 11 июня 2018 г. 18:14] - Какое ядро ​​вы использовали?
STM32Generic или STM Core?
Я попробовал оба. Наш код (OP) работает на STM Core, установленном в диспетчере платы. Я только изменил конфигурацию.H, в котором вы включаете определенные периферические (например, i2s и dma), это было необходимо для компиляции. I2S на самом деле «работает» в режиме опроса (блокировка процедуры записи), но сбои в режиме DMA, как объяснено выше (первый запрос DMA отправляет данные с количеством желаемых образцов, затем где -то блокирует ЦП)

Затем я попробовал общий код, предложенный выше, и собрал пример i2S (Simple Sattooth). Мне пришлось отложить задержку в основной петле, чтобы заставить его работать, но через некоторое время он все еще рухнул (возможно, когда весь буфер был отправлен)

Вот что я попытался скомпилироваться с общим ядром, и которое замерзает вскоре после сброса (с серийными отпечатками или без него). Я пытался реализовать с помощью SPI2 или SPI3. Спасибо
/* I2S sawtooth This example produces a digital sawtooth on the I2S interface for the microcontroller. If the microcontroller on your board supports an I2S interface ( not all do ) you can use e.g an Adafruit I2S amplifier with the MAX98357a chip to produce sound https://www.adafruit.com/product/3006 Check your microcontroller if it has an I2S interface. E.g. the STM32F103C8 ( on the BluePill board ) has no I2S On this board you can use only certain chips like the PT8211 16 Bit Digital to Analog Converter togehter with the SPI interface Pin description sd = DIN // I2S data ws = LRC // left/right channel ck = SCLK // serial data clock MCK = MCLK // master clock, some I2S chips ( like the CS42L22 ) need fast external clock provided by the MCU April 2017 ChrisMicro */ #include "I2S.h" // to use the example check your board schematic // if this is the correct pin setting for your board. // general setup without master clock //I2SClass I2S(SPI3, PC12 /*sd*/ , PA4 /*ws*/, PC10 /*ck*/); // setup with masterclock enabled I2SClass I2S(SPI3, PC12 /*sd*/ , PA4 /*ws*/, PC10 /*ck*/, PC7/* MCK*/); #define BUILTIN_LED PA5 #define USER_SWITCH PC13 //int led = 13; //int user_switch = 23; // PC13 = Digital Pin 23 void setup() { Serial.begin(115200); I2S.begin(I2S_PHILIPS_MODE, 44000, 16); pinMode(BUILTIN_LED, OUTPUT); pinMode(USER_SWITCH, INPUT); digitalWrite(BUILTIN_LED, HIGH); } void loop() { static uint16_t dacValue; I2S.write(dacValue); dacValue+=300; // saw tooth Serial.println("boo"); if(digitalRead(USER_SWITCH)) digitalWrite(BUILTIN_LED, HIGH); else digitalWrite(BUILTIN_LED, LOW); }

Chismicro
Ср 13 июня 2018 г., 4:23
Может случиться так, что F401RE в основном стволе структуры STM32GENEREN не так хорошо протестирован. Вероятно, есть более продвинутые филиалы от других людей, таких как Huaweiwx

https: // github.com/huaweiwx/stm32generic

или

K.Андерсон:
https: // github.com/ktand/stm32generic

Винсентп
Ср 13 июня 2018 г. 14:27
Я попробовал оба, Huaweiwx не компилируется (компилятор не понимает #endif, в то время как есть правильный IFDEF прямо выше, исправление одной вещи приводит к большему количеству проблем)

K Anderson Branch компилируется, как бывшая общая филиал, которую я пробовал, но обеспечивает те же проблемы: основной цикл не работает и не перестает бежать через некоторое время, если я позвоню в I2S написать.

В этот момент я нахожусь в конце концов: наш код, который называется базовая функция HAL, почти работает, но не ловит IRQ, и LIB должен работать (у кода много общего с нашим... :?

Chismicro
Ср 13 июня 2018 г., 17:12
Обычно общее ядро ​​работает довольно хорошо. Но может быть, некоторые MCU не так хорошо определены.

Например: i2s варианта black_f407ve работает очень хорошо.
Определения для этого варианта найдены здесь:
https: // github.com/danieleff/stm32gener ... ACK_F407VE

Определения ucleo401re найдены здесь:
https: // github.com/danieleff/stm32gener ... LEO_F401RE

РЕДАКТИРОВАТЬ: Я думаю, что в сценарии варианта не хватает инициализации I2S. Наверное, вы можете просто скопировать его из F407.

Chismicro
Солнце 17 июня 2018 г., 6:08
На моем доске i2s сейчас работает.
Я исправил варианты.C Инициализация и добавлена ​​два примера:
https: // github.com/chrismicro/stm32gene ... cleof401re
PLL-Setup скопирован из другого MCU, и я исправил его экспериментальный. Если у кого -то установлен конфигуратор часов STM32, он, вероятно, мог бы дать мне более точные значения.

Винсентп
Пн 18 июня 2018 г., 6:45
Большое спасибо за тестирование и исправление варианта, я попробую как можно скорее. Мы уже разработали значение для часов i2s. Я постараюсь сравнить и посмотреть, что не так с нашим кодом

Chismicro
Пт 22 июня 2018 г., 3:42
Спасибо за ответ. Мне любопытно в результате.