Перейти к содержанию
    

STM32H743 SPI-DMA

Пытаюсь включить SPI --- DMA в микроконтроллере STM32H7.  

Как понял из даташита на stm32h743 при передачи данных из ОЗУ в SPI данные пишутся в буфер FIFO - SPI. Получается что возможно установка флага конца передачи  DMA до момента конца передачи. И теперь непонятно когда можно формировать следующие посылку для передачи данных. В общем как понять что передача данных завершена и можно передавать новые данные?

Изменено пользователем Alex_Golubev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Именно по TC от DMA.
Чипселект разумеется не по этому событию снимать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вот если смотреть по TC от DMA.  То программа зависает, когда хочешь передать повторно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 буфера и переключал их. Уже не помню логику, но использовал оба прерывания конец передачи буфера и передача половины буфера. Только так у меня получилось передавать без задержек.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот простейший код работы с 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 просто зависал и не передавал данные. 

Изменено пользователем Alex_Golubev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...