Alex_Golubev 0 17 мая, 2021 Опубликовано 17 мая, 2021 (изменено) · Жалоба Пытаюсь включить SPI --- DMA в микроконтроллере STM32H7. Как понял из даташита на stm32h743 при передачи данных из ОЗУ в SPI данные пишутся в буфер FIFO - SPI. Получается что возможно установка флага конца передачи DMA до момента конца передачи. И теперь непонятно когда можно формировать следующие посылку для передачи данных. В общем как понять что передача данных завершена и можно передавать новые данные? Изменено 17 мая, 2021 пользователем Alex_Golubev Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 17 мая, 2021 Опубликовано 17 мая, 2021 · Жалоба Именно по TC от DMA. Чипселект разумеется не по этому событию снимать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex_Golubev 0 18 мая, 2021 Опубликовано 18 мая, 2021 · Жалоба Ну вот если смотреть по TC от DMA. То программа зависает, когда хочешь передать повторно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 18 мая, 2021 Опубликовано 18 мая, 2021 · Жалоба 12 hours ago, GenaSPB said: Именно по TC от DMA. Чипселект разумеется не по этому событию снимать. Чипселект на каждый байт вроде снимать надо. 15 hours ago, Alex_Golubev said: Пытаюсь включить SPI --- DMA в микроконтроллере STM32H7. Как понял из даташита на stm32h743 при передачи данных из ОЗУ в SPI данные пишутся в буфер FIFO - SPI. Получается что возможно установка флага конца передачи DMA до момента конца передачи. И теперь непонятно когда можно формировать следующие посылку для передачи данных. В общем как понять что передача данных завершена и можно передавать новые данные? Из общих соображений (деталей не знаю, а смотреть нет времени) Контроллеру DMA должна быть указана длина передаваемого буфера. После такого количества пересланых байт DMA контроллер скажет, что посылка передана и он готов к новой передаче. Еслу вы пользуетесь HAL, то есть проблема. Прерывания долго обрабатываются. Я когда-то на STM32 делал звуковой интерфейс на PCM и там я это обошел тем, что создал 2 буфера и переключал их. Уже не помню логику, но использовал оба прерывания конец передачи буфера и передача половины буфера. Только так у меня получилось передавать без задержек. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex_Golubev 0 18 мая, 2021 Опубликовано 18 мая, 2021 (изменено) · Жалоба Вот простейший код работы с spi через dma. Скрытый текст EEPROM_TX[0] = EEPROM_RDID; DMAMUX1_Channel5->CCR = (83 << DMAMUX_CxCR_DMAREQ_ID_Pos); // подключение MUXDMA spi4_rx_dma DMAMUX1_Channel6->CCR = (84 << DMAMUX_CxCR_DMAREQ_ID_Pos); // spi4_tx_dma DMA1_Stream5->CR &= ~DMA_SxCR_EN; // выключаем DMA while (DMA1_Stream5->CR & DMA_SxCR_EN); // ждем чтобы гарантировано был отключен DMA DMA1_Stream5->CR = DMA_SxCR_MINC; // инкремент памяти DMA1_Stream5->NDTR = 10; DMA1_Stream5->PAR = (uint32_t)&SPI4->RXDR; // адрес от куда брать данные DMA1_Stream5->M0AR = (uint32_t)&EEPROM_RX[0]; // указываем адрес массива куда писать DMA1_Stream6->CR &= ~DMA_SxCR_EN; // выключаем DMA while (DMA1_Stream6->CR & DMA_SxCR_EN); // ждем чтобы гарантировано был отключен DMA DMA1_Stream6->CR = DMA_SxCR_MINC | DMA_SxCR_DIR_0; // инкремент памяти, передача из памяти DMA1_Stream6->NDTR = 10; // количество данных для передачи DMA1_Stream6->PAR = (uint32_t)&SPI4->TXDR; // адрес от куда брать данные DMA1_Stream6->M0AR = (uint32_t)&EEPROM_TX[0]; // указываем адрес масива куда писать SPI4->CR1 = 0x00; SPI4->CFG1 = 0x00; SPI4->CFG1 = SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN | (0x7 << SPI_CFG1_DSIZE_Pos); SPI4->CFG2 = 0x00; SPI4->CFG2 = SPI_CFG2_SSOE | SPI_CFG2_MASTER | SPI_CFG2_MIDI_0 | SPI_CFG2_MSSI_0; SPI4->CR2 = 10; DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_SPE; while(!(SPI4->CR1&SPI_CR1_SPE)); SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; EEPROM_TX[0] = EEPROM_WRITE; EEPROM_TX[1] = 0x00; EEPROM_TX[2] = 0x00; EEPROM_TX[3] = 0xaa; EEPROM_TX[4] = 0xaa; EEPROM_TX[5] = 0xaa; EEPROM_TX[6] = 0xaa; SPI4->CR2 = 7; DMA1_Stream5->NDTR = 7; DMA1_Stream6->NDTR = 7; DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); // зависает DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; EEPROM_TX[0] = EEPROM_READ; EEPROM_TX[1] = 0x00; EEPROM_TX[2] = 0x00; EEPROM_TX[3] = 0x00; EEPROM_TX[4] = 0x00; EEPROM_TX[5] = 0x00; EEPROM_TX[6] = 0x00; SPI4->CR2 = 7; DMA1_Stream5->NDTR = 7; DMA1_Stream6->NDTR = 7; DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); // зависает DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; Зависает на проверки флага конца передачи DMA TC. Хотя первый пакет передает корректно. Получается счетчик dma NDTR зависает на значение 4 и счетчик spi4 -> SR.CTSIZE зависает на отметки 4. И данные не передаются. Система весит и ждет когда установится флаг TC в DMA. А он не установится так как DMA NDTR не равен нулю. Пошел по старинке и сделал управление NSS в виде программного дерганья ножки. Скрытый текст Выложил весь код для изучения. MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE6, 0x2 << GPIO_MODER_MODE6_Pos); // перевод порта на альтернативную функцию MOSI --- SI MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE5, 0x2 << GPIO_MODER_MODE5_Pos); // перевод порта на альтернативную функцию MISO --- SO //MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE4, 0x2 << GPIO_MODER_MODE4_Pos); // перевод порта на альтернативную функцию NSS --- CS MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE4, 0x1 << GPIO_MODER_MODE4_Pos); // перевод порта на альтернативную функцию NSS --- CS MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE3, 0x1 << GPIO_MODER_MODE3_Pos); // перевод порта на альтернативную функцию WR MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE2, 0x2 << GPIO_MODER_MODE2_Pos); // перевод порта на альтернативную функцию SCK MODIFY_REG(GPIOE->MODER, GPIO_MODER_MODE0, 0x1 << GPIO_MODER_MODE0_Pos); // перевод порта на альтернативную функцию HOLD MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED6, 0x2 << GPIO_OSPEEDR_OSPEED6_Pos); // настройка скорости фронта скорость наибольшая MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED5, 0x2 << GPIO_OSPEEDR_OSPEED5_Pos); // настройка скорости фронта MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED4, 0x2 << GPIO_OSPEEDR_OSPEED4_Pos); // настройка скорости фронта MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED3, 0x2 << GPIO_OSPEEDR_OSPEED3_Pos); // настройка скорости фронта MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED2, 0x2 << GPIO_OSPEEDR_OSPEED2_Pos); // настройка скорости фронта MODIFY_REG(GPIOE->OSPEEDR, GPIO_OSPEEDR_OSPEED0, 0x2 << GPIO_OSPEEDR_OSPEED0_Pos); // настройка скорости фронта MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD6, 0x00 << GPIO_PUPDR_PUPD6_Pos); // отключение подтяжки MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD5, 0x00 << GPIO_PUPDR_PUPD5_Pos); // отключение подтяжки MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD4, 0x00 << GPIO_PUPDR_PUPD4_Pos); // отключение подтяжки MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD3, 0x00 << GPIO_PUPDR_PUPD3_Pos); // отключение подтяжки MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD2, 0x00 << GPIO_PUPDR_PUPD2_Pos); // отключение подтяжки MODIFY_REG(GPIOE->PUPDR, GPIO_PUPDR_PUPD0, 0x00 << GPIO_PUPDR_PUPD0_Pos); // отключение подтяжки MODIFY_REG(GPIOE->AFR[0], GPIO_AFRL_AFSEL6, 0x5 << GPIO_AFRL_AFSEL6_Pos); // переключение на альтернативный режим работы порта AF5 MODIFY_REG(GPIOE->AFR[0], GPIO_AFRL_AFSEL5, 0x5 << GPIO_AFRL_AFSEL5_Pos); //MODIFY_REG(GPIOE->AFR[0], GPIO_AFRL_AFSEL4, 0x5 << GPIO_AFRL_AFSEL4_Pos); MODIFY_REG(GPIOE->AFR[0], GPIO_AFRL_AFSEL2, 0x5 << GPIO_AFRL_AFSEL2_Pos); SET_BIT(GPIOE->BSRR, GPIO_BSRR_BS0); SET_BIT(GPIOE->BSRR, GPIO_BSRR_BS3); SET_BIT(GPIOE->BSRR, GPIO_BSRR_BS4); EEPROM_TX[0] = EEPROM_RDID; DMAMUX1_Channel5->CCR = (83 << DMAMUX_CxCR_DMAREQ_ID_Pos); // подключение MUXDMA spi4_rx_dma DMAMUX1_Channel6->CCR = (84 << DMAMUX_CxCR_DMAREQ_ID_Pos); // spi4_tx_dma DMA1_Stream5->CR &= ~DMA_SxCR_EN; // выключаем DMA while (DMA1_Stream5->CR & DMA_SxCR_EN); // ждем чтобы гарантировано был отключен DMA DMA1_Stream5->CR = DMA_SxCR_MINC; // инкремент памяти DMA1_Stream5->NDTR = 10; DMA1_Stream5->PAR = (uint32_t)&SPI4->RXDR; // адрес от куда брать данные DMA1_Stream5->M0AR = (uint32_t)&EEPROM_RX[0]; // указываем адрес массива куда писать DMA1_Stream6->CR &= ~DMA_SxCR_EN; // выключаем DMA while (DMA1_Stream6->CR & DMA_SxCR_EN); // ждем чтобы гарантировано был отключен DMA DMA1_Stream6->CR = DMA_SxCR_MINC | DMA_SxCR_DIR_0; // инкремент памяти, передача из памяти DMA1_Stream6->NDTR = 10; // количество данных для передачи DMA1_Stream6->PAR = (uint32_t)&SPI4->TXDR; // адрес от куда брать данные DMA1_Stream6->M0AR = (uint32_t)&EEPROM_TX[0]; // указываем адрес масива куда писать SPI4->CR1 = 0x00; SPI4->CFG1 = 0x00; SPI4->CFG1 = SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN | (0x7 << SPI_CFG1_DSIZE_Pos); SPI4->CFG2 = 0x00; SPI4->CFG2 = SPI_CFG2_SSOE | SPI_CFG2_MASTER /*| SPI_CFG2_MIDI_0 | SPI_CFG2_MSSI_0*/; SPI4->CR2 = 0; SET_BIT(GPIOE->BSRR, GPIO_BSRR_BR4); DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_SPE; while(!(SPI4->CR1&SPI_CR1_SPE)); SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; SET_BIT(GPIOE->BSRR,GPIO_BSRR_BS4); EEPROM_TX[0] = EEPROM_WREN; EEPROM_TX[1] = 0x0; SPI4->CR2 = 0; DMA1_Stream5->NDTR = 1; DMA1_Stream6->NDTR = 1; SET_BIT(GPIOE->BSRR, GPIO_BSRR_BR4); DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; SET_BIT(GPIOE->BSRR,GPIO_BSRR_BS4); EEPROM_TX[0] = EEPROM_RDSR; EEPROM_TX[1] = 0x00; SPI4->CR2 = 0; DMA1_Stream5->NDTR = 2; DMA1_Stream6->NDTR = 2; SET_BIT(GPIOE->BSRR, GPIO_BSRR_BR4); DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; SET_BIT(GPIOE->BSRR,GPIO_BSRR_BS4); EEPROM_TX[0] = EEPROM_WRITE; EEPROM_TX[1] = 0x00; EEPROM_TX[2] = 0x00; EEPROM_TX[3] = 0xa5; EEPROM_TX[4] = 0xa5; EEPROM_TX[5] = 0xa5; EEPROM_TX[6] = 0xa5; SPI4->CR2 = 0; DMA1_Stream5->NDTR = 7; DMA1_Stream6->NDTR = 7; SET_BIT(GPIOE->BSRR, GPIO_BSRR_BR4); DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; SET_BIT(GPIOE->BSRR,GPIO_BSRR_BS4); EEPROM_TX[0] = EEPROM_READ; EEPROM_TX[1] = 0x00; EEPROM_TX[2] = 0x00; EEPROM_TX[3] = 0x00; EEPROM_TX[4] = 0x00; EEPROM_TX[5] = 0x00; EEPROM_TX[6] = 0x00; EEPROM_TX[7] = 0x00; SPI4->CR2 = 0; DMA1_Stream5->NDTR = 7; DMA1_Stream6->NDTR = 7; SET_BIT(GPIOE->BSRR, GPIO_BSRR_BR4); DMA1_Stream6->CR |= DMA_SxCR_EN; DMA1_Stream5->CR |= DMA_SxCR_EN; SPI4->CR1 |= SPI_CR1_CSTART; while(!(DMA1->HISR & DMA_HISR_TCIF6)); DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CFEIF6; while(!(DMA1->HISR & DMA_HISR_TCIF5)); DMA1->HIFCR |= DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; SPI4->IFCR = 0xFF8; SET_BIT(GPIOE->BSRR,GPIO_BSRR_BS4); Зависание больше нет проходит все этапы работы. Но почему не работала аппаратная NSS я не понял. SPI просто зависал и не передавал данные. Изменено 18 мая, 2021 пользователем Alex_Golubev Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться