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

Добрый день. 

Осваиваю SPI на МК H743.  Без использования DMA отправляю и получаю, все работает. Отправлять с DMA тоже получается, а вот с приемом какая-то странность.

Отправляю устройству 7 байт при помощи DMA2_Stream6, получаю при помощи DMA2_Stream5.

Инициализация DMA:

    RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;   // DMA2 clock enable;

    // Set the peripheral and memory addresses:
    DMA2_Stream6->PAR = (uint32_t) &(SPI1->TXDR);
    DMA2_Stream6->M0AR = (uint32_t )LIS3DH_CMD_LIST;
    DMA2_Stream6->CR = 0;
    DMA2_Stream6->CR |= (1u << DMA_SxCR_DIR_Pos)|\
    					 DMA_SxCR_MINC;

	DMA2_Stream6->NDTR = sizeof(LIS3DH_CMD_LIST); //DMA transfer length
    DMAMUX1_Channel14->CCR = 38; //SPI1_TX

    DMA2_Stream5->PAR = (uint32_t) &(SPI1->RXDR);
    DMA2_Stream5->M0AR = (uint32_t )response;
    DMA2_Stream5->CR = 0;
    DMA2_Stream5->CR |=  DMA_SxCR_MINC;
    					 
    DMA2_Stream5->NDTR = sizeof(LIS3DH_CMD_LIST); //DMA transfer length
    DMAMUX1_Channel13->CCR = 37; //SPI1_RX

Память с которой работает DMA находится в D2, выравнивание на 4 сделано, тактирование SRAM2 включено.

uint8_t RAM_D2 ALGN4 LIS3DH_CMD_LIST[] = {0xE8,0x0,0x0,0x0,0x0,0x0,0x0};
volatile uint8_t RAM_D2 ALGN4 response[sizeof(LIS3DH_CMD_LIST)];

В реф. мане описана процедура запуска передачи при помощи DMA, делаю как описано.:

Спойлер

1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CFG1 register, if DMA Rx is used.
2. Enable DMA requests for Tx and Rx in DMA registers, if the DMA is used.
3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CFG1 register, if DMA Tx is used.
4. Enable the SPI by setting the SPE bit. 

- отключаю SPI для изменения CFG1

- Устанавливаю в CR2 количество байт в пакете, чтобы по окончанию поднялся CS

- Включаю RXDMAEN (п.1)

- Включаю DMA (п.2)

- Включаю TXDMAEN (п.3)

- Включаю SPI (п.4)

В таком варианте передача не начинается, надо еще CSTART бит выставить.

	SPI1->CR1 &= ~SPI_CR1_SPE;
	SPI1->CR2 = 7;
	SPI1->CFG1 |= SPI_CFG1_RXDMAEN;
	//RX
	DMA2_Stream5 -> CR |= DMA_SxCR_EN;
	//TX
	DMA2_Stream6 -> CR |= DMA_SxCR_EN;

	SPI1->CFG1 |= SPI_CFG1_TXDMAEN;
	SPI1->CR1 |= SPI_CR1_SPE;

	SPI1->CR1 |= SPI_CR1_CSTART;	

Результат проверяю по флагам DMA шагая в отладчике и в логическом анализаторе.

После включения SPI1->CR1 |= SPI_CR1_SPE устанавливаются флаги:

TCIF6, HTIF6 (dma передачи) и это вроде понятно. А так же флаги TCIF5 и HTIF5 (dma приема) и это совсем не понятно.

Физической передачи при этом не происходит. С передачей, как я понимаю, DMA отправляет все в FIFO SPI и поэтому выставляет флаги окончания. После выставления флага CSTART происходит реальная передача в шину. Я в лог. анализаторе вижу именно то, что и ожидаю.

А вот с флагами DMA на прием я не понимаю, почему после включения SPI_CR1_SPE DMA выставляет флаги окончания, если ничего еще не было передано. И выглядит все так, как-будто передача действительно была, NDTR становится в 0. Но реальной передачи еще не было и флаг RXP в SPI не поднимался.

Реальная передача, после выставления CSTART уже естественно ничего не меняет в приемном DMA. А в регистрах SPI я как раз вижу, что после передачи принятые данные остались в FIFO, стоит RXP.

Что я делаю не правильно?

 

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


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

Не работал с H7, но правильно ли выставлен источник событий для DMA2_Stream5? Может какая-то другая периферия вместо SPI заставляет DMA2_Stream5 делать пересылку?

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


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

Это устанавливается при помощи DMAMUX. 

DMAMUX1_Channel13->CCR = 37; //SPI1_RX

Каналы DMAMUX связаны с каналами DMA. Связь там вот такая:

DMAMUX1 channels 0 to 7 are connected to DMA1 channels 0 to 7
DMAMUX1 channels 8 to 15 are connected to DMA2 channels 0 to 7
DMAMUX2 channels 0 to 7 are connected to BDMA channels 0 to 7
  
Или проще говоря:


DMA1_Stream_x -> DMAMUX1_Channel_x
DMA2_Stream_x -> DMAMUX1_Channel_(x+8)

А к чему конкретно из периферии будет подключен канал DMA устанавливается в CCR регистре DMAMUX. Для каждого источника свой номер, они в RM указаны. Для DMAMUX1 в моем случае это: 

37 spi1_rx_dma
38 spi1_tx_dma

 

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


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

Похоже что эта проблема описана в Errata. По описанию я сразу не признал "Spurious DMA Rx transaction after simplex Tx traffic"

Решение - сброс SPI перед включением DMA на прием. Сброс через SPE бит не помогает, делаю 

RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
__NOP();
RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST;

После этого, естественно, надо снова инициализировать SPI.

В новых ревизиях вроде бы поправили.

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


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

Я могу попросить показать инициализацию SPI? Все сделал по инструкции, но не работает. Опытным путем определил, что пины спиаем не управляются. Пины рабочие, простым дерганием меандр получаю. Хочу узнать что не так делаю. Кстати куб тоже не дает результата. Что вручную, что кубом, все одно и тоже. Не работает. Подскажите, что я не учел? Может в коде увижу. Спасибо.

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


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

	// Настроим модуль SPI.
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // подать тактирование
	(void) RCC->APB2ENR;
	//SPI1->CR1 = 0x0000;             //очистить первый управляющий регистр
	//SPI1->CR2 = 0x0000;

	#if WITHSPIHWDMA
		DMA2_SPI1_TX_initialize();
		DMA2_SPI1_RX_initialize();
	#endif /* WITHSPIHWDMA */

	/* настраиваем в режиме disconnect */
	SPIIO_INITIALIZE();

 

Подгттовка параметрв для разнфз режимов и скоростей:


	unsigned value;	/* делителя нет, есть только прескалер - значение делителя не используется */
	const uint_fast8_t prei = calcdivider(calcdivround_per_ck(spispeed), STM32F_SPIBR_WIDTH, STM32F_SPIBR_TAPS, & value, 1);
	const uint_fast32_t cfg1baudrate = (prei * SPI_CFG1_MBR_0) & SPI_CFG1_MBR_Msk;
	const uint_fast32_t cfg1 = cfg1baudrate;// | (SPI_CFG1_CRCSIZE_0 * 7);
	//PRINTF(PSTR("hardware_spi_master_setfreq: prei=%u, value=%u, spispeed=%u\n"), prei, value, spispeed);

	spi_cfg1_val8w [spispeedindex] = cfg1 |
		7 * SPI_CFG1_DSIZE_0 |
		0;

	spi_cfg1_val16w [spispeedindex] = cfg1 |
		15 * SPI_CFG1_DSIZE_0 |
		0;

	spi_cfg1_val32w [spispeedindex] = cfg1 |
		31 * SPI_CFG1_DSIZE_0 |
		0;

	const uint_fast32_t cfg2bits =
			SPI_CFG2_SSOM_Msk |
			SPI_CFG2_SSOE_Msk |
			SPI_CFG2_SSM_Msk |	// 1: SS input value is determined by the SSI bit
			SPI_CFG2_MASTER_Msk |
			SPI_CFG2_AFCNTR_Msk | // 1: the peripheral keeps always control of all associated GPIOs
			0;
	enum
	{
		CFG2_MODE0 = 0,				// TODO: not tested
		CFG2_MODE1 = SPI_CFG2_CPHA_Msk,	// TODO: not tested
		CFG2_MODE2 = SPI_CFG2_CPOL_Msk,	// CLK leave HIGH
		CFG2_MODE3 = SPI_CFG2_CPOL_Msk | SPI_CFG2_CPHA_Msk		// wrk = CLK leave "HIGH"
	};

	// подготовка управляющих слов для разных spi mode, используемых контроллером.
	// 8-битная или 16-битная передача программируется в CR2
	spi_cfg2_val [SPIC_MODE0] = cfg2bits | CFG2_MODE0;
	spi_cfg2_val [SPIC_MODE1] = cfg2bits | CFG2_MODE1;
	spi_cfg2_val [SPIC_MODE2] = cfg2bits | CFG2_MODE2;
	spi_cfg2_val [SPIC_MODE3] = cfg2bits | CFG2_MODE3;

 

Передв 8-бит обменами:


	HARDWARE_SPI_CONNECT();

	SPI1->CFG1 = spi_cfg1_val8w [spispeedindex];
	SPI1->CFG2 = spi_cfg2_val [spimode];
	SPI1->CR1 |= SPI_CR1_SSI;

	SPI1->CR1 |= SPI_CR1_SPE;
	SPI1->CR1 |= SPI_CR1_CSTART;

Отключаемся:


	SPI1->CR1 |= SPI_CR1_CSUSP;
	while ((SPI1->CR1 & SPI_CR1_CSTART) != 0)
		;
	SPI1->CR1 &= ~ SPI_CR1_SPE;
	// connect back to GPIO
	HARDWARE_SPI_DISCONNECT();

hftrx/hardware.c at master · ua1arn/hftrx (github.com)

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

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


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

Это присоединение контроллера SPI к выводам проессора в соответствии с альтернативными функциями.

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


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

SPI похоже заработал. Инициализировал и гоняю 16 бит с проверкой флага TXC. Уходит.  С ДМА не пробовал пока.

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


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

А что было то?

Если с программным опросом правильнее rxp ждать (и сбрасывать его чтением данных ). 

Опять же ждать эффективнее по скорости перед передачей не первый раз.

Мне не интересно. Но кому-то может помочь.

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

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


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

Да так и не понял. Выкинул все и оставил в цикле запись на передачу по флагу завершения передачи. Все и заработало. Завтра выложу если интересно. Купился по сути на танцы куба и других примеров. Через некоторое время сделаю передачу-прием буферов. Пока другое надо подтянуть.

Усарт кстати просто с ходу заработал. Там все просто.

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


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

У меня и без DMA нормально не работает(H750 Rev. V)... Суть проблемы в следующем, допустим у SPI 16 байт FIFO, соединяем MISO с MOSI и отправляем 16 байт, без чтения, затем читаем все 16(они правильные), отправляем еще один байт и его принимаем, все работает. Но если отправить больше 16 байт, допустим 17, то устанавливает флаг OVR, в документации сказано, что в таком случае его нужно сбросить и вычитать FIFO, но если после этого отправить очередной байт, то он уходит, но ничего не принимается. После отправки следующего байта принимается уже он. Проблему решает отключение SPI, т.к. при этом происходит сброс машины состояний, но тогда дергается NSS и это не всегда приемлемо...

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

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


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

В 27.11.2019 в 14:46, sst78rus сказал:

Добрый день. 

Осваиваю SPI на МК H743.  Без использования DMA отправляю и получаю, все работает. Отправлять с DMA тоже получается, а вот с приемом какая-то странность.

Отправляю устройству 7 байт при помощи DMA2_Stream6, получаю при помощи DMA2_Stream5.

Инициализация DMA:

    RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;   // DMA2 clock enable;

    // Set the peripheral and memory addresses:
    DMA2_Stream6->PAR = (uint32_t) &(SPI1->TXDR);
    DMA2_Stream6->M0AR = (uint32_t )LIS3DH_CMD_LIST;
    DMA2_Stream6->CR = 0;
    DMA2_Stream6->CR |= (1u << DMA_SxCR_DIR_Pos)|\
    					 DMA_SxCR_MINC;

	DMA2_Stream6->NDTR = sizeof(LIS3DH_CMD_LIST); //DMA transfer length
    DMAMUX1_Channel14->CCR = 38; //SPI1_TX

    DMA2_Stream5->PAR = (uint32_t) &(SPI1->RXDR);
    DMA2_Stream5->M0AR = (uint32_t )response;
    DMA2_Stream5->CR = 0;
    DMA2_Stream5->CR |=  DMA_SxCR_MINC;
    					 
    DMA2_Stream5->NDTR = sizeof(LIS3DH_CMD_LIST); //DMA transfer length
    DMAMUX1_Channel13->CCR = 37; //SPI1_RX

Память с которой работает DMA находится в D2, выравнивание на 4 сделано, тактирование SRAM2 включено.

uint8_t RAM_D2 ALGN4 LIS3DH_CMD_LIST[] = {0xE8,0x0,0x0,0x0,0x0,0x0,0x0};
volatile uint8_t RAM_D2 ALGN4 response[sizeof(LIS3DH_CMD_LIST)];

В реф. мане описана процедура запуска передачи при помощи DMA, делаю как описано.:

  Показать контент

1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CFG1 register, if DMA Rx is used.
2. Enable DMA requests for Tx and Rx in DMA registers, if the DMA is used.
3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CFG1 register, if DMA Tx is used.
4. Enable the SPI by setting the SPE bit. 

 

 

Что я делаю не правильно?

 

Здравствуйте .

Я раньше на стм32ф4 успешно сделал был вывод по SPI MOSI через DMA, когда завершалась передача ДМА я генерировал прерывание и переключал свободный пин светодиода - моргал светодиодом.

Теперь решил тоже самое на STM32H743 сделать. Нашел пример куба для SPI_FullDuplex_ComDMA и по примеру него написал свой код, чтобы моргать светодиодом.

Но почемуто не запускается у меня передача по ДМА и не заходит во внутрь функции прерываний.

Вы можете мне показать свой код, как вы настраивали SPI  DMA  ?

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


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

добрый всем,

Может кто подскажет, перешол на stm32h7b0

добрый всем,

Может кто подскажет, перешол на stm32h7b0  не могу не как разобратся с SPI такое чуства что карнел_клок не поступает.

 movw r0,#RCC_L
    movt r0,#RCC_H
    ldr r1,[r0,#RCC_CDCCIP1R_B]
    bic r1,#SPI123SEL_MASK
    orr r1,#SPI123SEL_PER        ;
    str r1,[r0,#RCC_CDCCIP1R_B]    
    
    
    ldr r1,[r0,#RCC_APB1LENR_B]
    orr r1,#SPI3                        ;enable spi3 clk in 
    str r1,[r0,#RCC_APB1LENR_B]    


    movw r0,#SPI3_L
    movt r0,#SPI3_H

    mov32 r1,#(MBR_DIV2+0x7)        ;clc/2 8bit lenght
    str r1,[r0,#SPI_CFG1_B]    
    

    ;enable spi
    mov r1,#(MASTER|SSOE)        ;
    str r1,[r0,#SPI_CFG2_B]    
    
    
    ldr r1,[r0,#SPI_CR1_B]    ;enable spi
    orr r1,#(SPE)            
    str r1,[r0,#SPI_CR1_B]

Модератор: если русский язык не Ваш родной, лучше укажите в профиле местоположение, в противном случае пишите грамотно. Иначе - это нарушение правил.

Изменено пользователем haker_fox
Для оформления кода есть кнопка <>.

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


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

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

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

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

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

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

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

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

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

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