DMA+SPI+STM32f103. Трабл с прерыванием.

Кто любит RISC в жизни, заходим, не стесняемся.
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

Доброго. Настраиваю связку DMA+SPI на чтение. Проблема в том, что прога не заходит в прерывание по окончании приёма DMA. Но при этом SPI посылает запрос на чтение и принимает ответ от микрухи (смотрел логическим анализатором). Может, кто заметит, в чём косяк? (Возможно, на SPL и HAL было бы быстрее и проще, но я их не люблю). Код следующий:

Код: Выделить всё

uint8_t dma_answ[5] = {0};

void clock_init(){
	RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_SW);         
  RCC->CR   &= ~RCC_CR_PLLON;            
  RCC->CFGR |=  RCC_CFGR_SW_PLL;         
  RCC->CFGR &= ~RCC_CFGR_PLLMULL;        
  RCC->CFGR |=  RCC_CFGR_PLLMULL9;// | RCC_CFGR_PLLSRC ;        
  RCC->CR   |=  RCC_CR_PLLON | RCC_CR_HSEON;             
  while((RCC->CR & RCC_CR_PLLRDY)==0);  
}

void SPI_Init(uint8_t lsbFirst, uint8_t clockPol, uint8_t clockEdg){
	
	RCC->APB2ENR |=  RCC_APB2ENR_AFIOEN; 	// Тактирование альтернативных функций включено
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  	// Тактирование порта А включено

	
//------- TEST-PIN ----------------
        GPIOA->CRH   |=  GPIO_CRH_MODE12;   	// Выход, 50 МГц
	GPIOA->CRH   &= ~GPIO_CRH_CNF12;       // Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BR12;
//---------------------------------
	
	
//------- CS-PIN ------------------
        GPIOA->CRL   |=  GPIO_CRL_MODE4;        // Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF4;     	// Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BS4;     	// Высокий уровень
//---------------------------------

//------- SCK-PIN -----------------	
	GPIOA->CRL   |=  GPIO_CRL_MODE5;    	// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF5;     	
	GPIOA->CRL   |=  GPIO_CRL_CNF5_1;   	// Альтернативная функция, push-pull
//---------------------------------
	
//------- MISO-PIN ----------------	
	GPIOA->CRL   &= ~GPIO_CRL_MODE6;			// Вход    
	GPIOA->CRL   &= ~GPIO_CRL_CNF6;     
	GPIOA->CRL   |=  GPIO_CRL_CNF6_1;   	// Альтернативная функция, pull-up/pull-down
	GPIOA->BSRR   =  GPIO_BSRR_BS6;     	// Высокий уровень
//---------------------------------

//------- MOSI-PIN ----------------
	GPIOA->CRL   |=  GPIO_CRL_MODE7; 			// Выход, 50 МГц   
	GPIOA->CRL   &= ~GPIO_CRL_CNF7;     	
	GPIOA->CRL   |=  GPIO_CRL_CNF7_1;   	// Альтернативная функция, push-pull
//---------------------------------	 

	SPI1->CR1     = 0x0000;		// Обнуляем регистр конфигурации SPI1            
	SPI1->CR2     = 0x0000;		// Обнуляем регистр конфигурации SPI1 

	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		// Тактирование SPI1 включено
	
	SPI1->CR1 = SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_MSTR;		// Программное управление выводом CS, SPI1 в режиме ведущего
	
	if(!lsbFirst) 	SPI1->CR1 &= ~SPI_CR1_LSBFIRST;		// Старшим битом вперёд
	else			SPI1->CR1 |=  SPI_CR1_LSBFIRST;  	        // Младшим битом вперёд
	
	if(!clockPol)	SPI1->CR1 &= ~SPI_CR1_CPOL;			// 0 - когда отпущена
	else			SPI1->CR1 |=  SPI_CR1_CPOL;				// 1 - когда отпущена
	
	if(!clockEdg)	SPI1->CR1 &= ~SPI_CR1_CPHA;			// Выборка по переднему фронту
	else			SPI1->CR1 |=  SPI_CR1_CPHA;				// Выборка по заднему фронту
	
	
	SPI1->CR2 |= SPI_CR2_RXDMAEN;

	
	SPI1->CR1 |=   SPI_CR1_BR_1 | SPI_CR1_BR_0 ;		// Выбор делителя частоты тактирования шины APB2 (fAPB/16 = 2.25 МГц) 
	SPI1->CR1 |= 	SPI_CR1_SPE;						// Работа SPI1 разрешена
	
	NVIC_EnableIRQ(SPI1_IRQn);
	
	
}

void dma_spi_recive( uint8_t* data, uint8_t bytesNumber ){
	RCC->AHBENR = RCC_AHBENR_DMA1EN;
	
	DMA1_Channel2->CCR = 0x0F;
	
	DMA1_Channel2->CPAR 	= (uint32_t) & SPI1->DR;
	DMA1_Channel2->CMAR 	= (uint32_t) dma_answ;
	DMA1_Channel2->CNDTR 	= bytesNumber;
	
	
	DMA1_Channel2->CCR |=  DMA_CCR2_PL_0 | DMA_CCR2_MINC | DMA_CCR2_TCIE | DMA_CCR2_EN;
	
	
	
	NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}

uint8_t SPI_Read( uint8_t data, uint8_t bytesNumber ){
	
	dma_spi_recive(dma_answ, bytesNumber);
	ADI_PART_CS_LOW;
	
	
	while (!(SPI1->SR & SPI_SR_TXE));
	SPI1->DR = data;
	
	for(uint8_t byte = 0; byte < bytesNumber; byte++ )
	{
		while (!(SPI1->SR & SPI_SR_TXE));
		SPI1->DR = 0x00;
				
	}
	
	while ( SPI1->SR & SPI_SR_BSY ); 
	ADI_PART_CS_HIGH;
	
	return 1;
}

uint8_t SPI_Read( uint8_t data, uint8_t bytesNumber ){
	
	dma_spi_recive(dma_answ, bytesNumber);
	ADI_PART_CS_LOW;
	
	
	while (!(SPI1->SR & SPI_SR_TXE));
	SPI1->DR = data;
	
	for(uint8_t byte = 0; byte < bytesNumber; byte++ )
	{
		while (!(SPI1->SR & SPI_SR_TXE));
		SPI1->DR = 0x00;
				
	}
	
	while ( SPI1->SR & SPI_SR_BSY ); 
	ADI_PART_CS_HIGH;
	
	return 1;
}


uint32_t AD7190_GetRegisterValue(uint8_t registerAddress){
	
		uint8_t  registerWord = 0;
		uint32_t buffer = 0;
					 
		registerWord = AD7190_COMM_READ | AD7190_COMM_ADDR( registerAddress ); 
		
	
//-- Проверяем, какой длины считываемый регистр -------------------------------	
		if(	registerAddress == AD7190_REG_STAT || 
				registerAddress == AD7190_REG_ID || 
				registerAddress == AD7190_REG_GPOCON )   // если регистры однобайтные
		{	
		
				SPI_Read(registerWord, 1);
		

		}      
			
		else																			// если регистры трёхбайтные
		{
			
				SPI_Read(registerWord, 3);
							
		}
//---------------------------------------------------------------------------
	
    return buffer;
}


unsigned char AD7190_Init(void){
    unsigned char status = 1;
    unsigned long regVal = 0;
        	
		AD7190_Reset();
	
    regVal = AD7190_GetRegisterValue(AD7190_REG_ID);
	
		if( regVal != ID_AD7190)
    {
				return status = 0;
		}
		
		GPIOA->BSRR   =  GPIO_BSRR_BS12;     	// Высокий уровень
			
    return status ;
}


void AD7190_Reset(void){
	
	for( uint8_t byte = 0; byte <6; byte++ )
	{		
		while (!(SPI1->SR & SPI_SR_TXE));
		SPI1->DR = 0xFF; 
	} // Посылаем 40 импульсов для сброса
				
		
	TIME_DelayUs(920);
}
int main(){
clock_init();
	
	
	for(uint32_t i=0; i<720000; i++);
	SPI_Init(0, 1, 1);
	usart_init();

	
	AD7190_Init();
	
	AD7190_GetRegisterValue(AD7190_REG_CONF);

	
	__enable_irq ();

while(1){
		

	}
}

void DMA1_Channel2_IRQHandler(void){
	if(DMA1->ISR & DMA_ISR_TCIF2){
		DMA1_Channel2->CCR &= ~DMA_CCR2_EN;
	//	Flag = 1;
		if(!(GPIOA->IDR & GPIO_IDR_IDR12))	GPIOA->BSRR   =  GPIO_BSRR_BS12;
		else GPIOA->BSRR   =  GPIO_BSRR_BR12;
		
		DMA1->IFCR = DMA_IFCR_CGIF2;
	}
		
}
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение uk8amk »

Я увидел ошибку конфигурации DMA. Канал нельзя настраивать когда он включён.
In order
to reload a new number of data items to be transferred into the DMA_CNDTRx register, the
DMA channel must be disabled.
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

Да, безусловно. Там должно было быть

Код: Выделить всё

 DMA1_Channel2->CCR = 0x00; 
.

Исправил, подчистил код, та же фигня - прерывания от DMA не происходит. Никакого. Даже ошибки передачи. Может, что-то где-то ещё надо разрешать? Прерывания по завершению транзакции DMA разрешены, глобальные разрешены.

Код: Выделить всё

#include "stm32f10x.h"                  // Device header
#include "AD7190.h"
#include "TIME.h"  

#define DMA_EN	DMA1_Channel2->CCR |=  DMA_CCR2_EN
#define DMA_DIS	DMA1_Channel2->CCR &= ~DMA_CCR2_EN

//--------- SPI -------
volatile uint8_t SpiByteCnt = 0;
uint8_t SpiDataRX[5] = {0};
uint8_t dma_answ[5] = {0};

void clock_init(){
	RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_SW);         
  RCC->CR   &= ~RCC_CR_PLLON;            
  RCC->CFGR |=  RCC_CFGR_SW_PLL;         
  RCC->CFGR &= ~RCC_CFGR_PLLMULL;        
  RCC->CFGR |=  RCC_CFGR_PLLMULL9;     
  RCC->CR   |=  RCC_CR_PLLON | RCC_CR_HSEON;             
  while((RCC->CR & RCC_CR_PLLRDY)==0);  
}



void usart_init(){
	RCC->APB2ENR	|= RCC_APB2ENR_USART1EN;											//USART1 Clock ON
	RCC->APB2ENR 	|= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; 	// GPIOA Clock ON. Alter function clock ON
	
	USART1->BRR = 0xEA6;																														// Bodrate for 9600 on 72Mhz
	USART1->CR1 	|= USART_CR1_UE | USART_CR1_TE;	// USART1 ON, TX ON, RX ON
			
	GPIOA->CRH	&= ~GPIO_CRH_CNF9; 		// Clear CNF bit 9
	GPIOA->CRH	|= GPIO_CRH_CNF9_1;		// Set CNF bit 9 to 10 - AFIO Push-Pull
	GPIOA->CRH	|= GPIO_CRH_MODE9_0;	// Set MODE bit 9 to Mode 01 = 10MHz
	
	GPIOA->CRH	&= ~GPIO_CRH_CNF10;		// Clear CNF bit 9
	GPIOA->CRH	|= GPIO_CRH_CNF10_0;	// Set CNF bit 9 to 01 = HiZ
	GPIOA->CRH	&= ~GPIO_CRH_MODE10;	// Set MODE bit 9 to Mode 01 = 10MHz

//	NVIC_EnableIRQ(USART1_IRQn);			// USART1 interrupt enable
}

void usart_tx(uint8_t data){

	USART1->DR = data;
	while(!(USART1->SR & USART_SR_TC));
}


uint8_t SPI_Init(uint8_t lsbFirst, uint8_t clockPol, uint8_t clockEdg){
	
	RCC->APB2ENR |=  RCC_APB2ENR_AFIOEN; 	// Тактирование альтернативных функций включено
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  	// Тактирование порта А включено

	
//------- TEST-PIN ----------------
  GPIOA->CRH   |=  GPIO_CRH_MODE12;   	// Выход, 50 МГц
	GPIOA->CRH   &= ~GPIO_CRH_CNF12;      // Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BR12;
//---------------------------------
	
	
//------- CS-PIN ------------------
  GPIOA->CRL   |=  GPIO_CRL_MODE4;   		// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF4;     	// Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BS4;     	// Высокий уровень
//---------------------------------

//------- SCK-PIN -----------------	
	GPIOA->CRL   |=  GPIO_CRL_MODE5;    	// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF5;     	
	GPIOA->CRL   |=  GPIO_CRL_CNF5_1;   	// Альтернативная функция, push-pull
//---------------------------------
	
//------- MISO-PIN ----------------	
	GPIOA->CRL   &= ~GPIO_CRL_MODE6;			// Вход    
	GPIOA->CRL   &= ~GPIO_CRL_CNF6;     
	GPIOA->CRL   |=  GPIO_CRL_CNF6_1;   	// Альтернативная функция, pull-up/pull-down
	GPIOA->BSRR   =  GPIO_BSRR_BS6;     	// Высокий уровень
//---------------------------------

//------- MOSI-PIN ----------------
	GPIOA->CRL   |=  GPIO_CRL_MODE7; 			// Выход, 50 МГц   
	GPIOA->CRL   &= ~GPIO_CRL_CNF7;     	
	GPIOA->CRL   |=  GPIO_CRL_CNF7_1;   	// Альтернативная функция, push-pull
//---------------------------------	 

	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		// Тактирование SPI1 включено
	
	SPI1->CR1 = SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_MSTR;		// Программное управление выводом CS, SPI1 в режиме ведущего
	
	if(!lsbFirst) 	SPI1->CR1 &= ~SPI_CR1_LSBFIRST;		// Старшим битом вперёд
	else						SPI1->CR1 |=  SPI_CR1_LSBFIRST;  	// Младшим битом вперёд
	
	if(!clockPol)		SPI1->CR1 &= ~SPI_CR1_CPOL;				// 0 - когда отпушена
	else						SPI1->CR1 |=  SPI_CR1_CPOL;				// 1 - когда отпущена
	
	if(!clockEdg)		SPI1->CR1 &= ~SPI_CR1_CPHA;				// Выборка по переднему фронту
	else						SPI1->CR1 |=  SPI_CR1_CPHA;				// Выборка по заднему фронту
			
	SPI1->CR1 |=   	SPI_CR1_BR_1 | SPI_CR1_BR_0;			// Выбор делителя частоты тактирования шины APB2 (fAPB/16 = 2.25 МГц) 
	SPI1->CR1 |= 		SPI_CR1_SPE;											// Работа SPI1 разрешена
		
	SPI1->CR2 = SPI_CR2_RXDMAEN;
	
	return 1;
}

void dma_spi_recive( uint8_t bytesNumber ){
	RCC->AHBENR = RCC_AHBENR_DMA1EN;
	
	DMA1_Channel2->CCR = 0x00;
	
	DMA1_Channel2->CPAR 	= (uint32_t) & SPI1->DR;
	DMA1_Channel2->CMAR 	= (uint32_t) dma_answ;
	DMA1_Channel2->CNDTR 	= bytesNumber;
		
	DMA1_Channel2->CCR |=  DMA_CCR2_PL_0 | DMA_CCR2_MINC | DMA_CCR2_TCIE;
		
	NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}




int main(){
	uint8_t init = 0, registerWord[5] = {0};
	
	clock_init();
	SPI_Init(0, 1, 1);
	usart_init();
	
	__enable_irq ();
		
	while(1){
		
		if(!init){
			
			for( uint8_t byte = 0; byte <6; byte++ ){		
				while (!(SPI1->SR & SPI_SR_TXE));
				SPI1->DR = 0xFF; 
			} 
	
			while ( SPI1->SR & SPI_SR_BSY );			
		
			TIME_DelayUs(920);
			
			registerWord[0] = AD7190_COMM_READ | AD7190_COMM_ADDR( AD7190_REG_ID );
			
			ADI_PART_CS_LOW;
			
			while (!(SPI1->SR & SPI_SR_TXE));
			SPI1->DR = registerWord[0];
			while ( SPI1->SR & SPI_SR_BSY );
					
			dma_spi_recive(1);
					
			DMA_EN;
						
			init = 1;
		}
	}
}


void DMA1_Channel2_IRQHandler (void) 
{
	if(DMA1->ISR & DMA_ISR_TCIF2){

		ADI_PART_CS_HIGH;
		
		if(!(GPIOA->IDR & GPIO_IDR_IDR12))	GPIOA->BSRR   =  GPIO_BSRR_BS12;
		else GPIOA->BSRR   =  GPIO_BSRR_BR12;
		
		DMA_DIS;
		
		NVIC_DisableIRQ(DMA1_Channel2_IRQn);
		
		DMA1->IFCR = DMA_IFCR_CGIF2;
	}
}



Добавлено after 3 hours 48 minutes 37 seconds:
Столкнулся с магией: написал всю эту либилерду в КОКОСЕ и она заработала!!! В Кейле же прерываний как не было так и нет! За что меня так наказали? Код, который работает в КОКОСЕ

Код: Выделить всё

#include "stm32f10x.h"


#define AD7195_CS_HIGH		GPIOA->BSRR  |=   GPIO_BSRR_BS4
#define AD7195_CS_LOW			GPIOA->BSRR  |=   GPIO_BSRR_BR4

#define	DMA_SPI_TX_ENABLE 	DMA1_Channel3->CCR |=  DMA_CCR3_EN;
#define	DMA_SPI_TX_DISABLE 	DMA1_Channel3->CCR &= ~DMA_CCR3_EN;

#define	DMA_SPI_RX_ENABLE 	DMA1_Channel2->CCR |=  DMA_CCR2_EN;
#define	DMA_SPI_RX_DISABLE 	DMA1_Channel2->CCR &= ~DMA_CCR3_EN;

uint8_t GlobalVar_SPI_Received = 0, get[5];

void GPIO_INIT(){
	RCC->APB2ENR |=  RCC_APB2ENR_AFIOEN; 	// Тактирование альтернативных функций включено
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  	// Тактирование порта А включено


	//------- TEST-PIN ----------------
	GPIOA->CRH   |=  GPIO_CRH_MODE12;   	// Выход, 50 МГц
	GPIOA->CRH   &= ~GPIO_CRH_CNF12;      // Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BR12;
	//---------------------------------


	//------- CS-PIN ------------------
	GPIOA->CRL   |=  GPIO_CRL_MODE4;   		// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF4;     	// Общего назначения, push-pull
	GPIOA->BSRR   =  GPIO_BSRR_BS4;     	// Высокий уровень
	//---------------------------------

	//------- SCK-PIN -----------------
	GPIOA->CRL   |=  GPIO_CRL_MODE5;    	// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF5;
	GPIOA->CRL   |=  GPIO_CRL_CNF5_1;   	// Альтернативная функция, push-pull
	//---------------------------------

	//------- MISO-PIN ----------------
	GPIOA->CRL   &= ~GPIO_CRL_MODE6;			// Вход
	GPIOA->CRL   &= ~GPIO_CRL_CNF6;
	GPIOA->CRL   |=  GPIO_CRL_CNF6_1;   	// Альтернативная функция, pull-up/pull-down
	GPIOA->BSRR   =  GPIO_BSRR_BS6;     	// Высокий уровень
	//---------------------------------

	//------- MOSI-PIN ----------------
	GPIOA->CRL   |=  GPIO_CRL_MODE7; 			// Выход, 50 МГц
	GPIOA->CRL   &= ~GPIO_CRL_CNF7;
	GPIOA->CRL   |=  GPIO_CRL_CNF7_1;   	// Альтернативная функция, push-pull
	//---------------------------------

	AD7195_CS_HIGH;
}

void SPI_INIT(){
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		// Тактирование SPI1 включено

	SPI1->CR1 = SPI_CR1_SSI  | SPI_CR1_SSM  | 					// Программное управление выводом CS
				SPI_CR1_BR_1 | SPI_CR1_BR_0 | 					// Выбор делителя частоты тактирования шины APB2
				SPI_CR1_CPOL | SPI_CR1_CPHA | SPI_CR1_MSTR;		// 1 - когда CLK отпущена, выборка по заднему фронту, SPI1 в режиме ведущего

	SPI1->CR1 |= SPI_CR1_SPE;									// Работа SPI1 разрешена
}


void dma_spi_tx(uint8_t * data, uint16_t size) {
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;

	DMA1_Channel3->CPAR 	= (uint32_t) & SPI1->DR;
	DMA1_Channel3->CMAR 	= (uint32_t) data;
	DMA1_Channel3->CNDTR 	= size;

	DMA1_Channel3->CCR = DMA_CCR3_PL_0 | DMA_CCR3_MINC | DMA_CCR3_DIR | DMA_CCR3_TCIE;

    SPI1->CR2 |= SPI_CR2_TXDMAEN;

    NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}

void SPI_SendData(uint8_t *data, uint8_t size) {
	dma_spi_tx(data, size);
    AD7195_CS_LOW;

    DMA_SPI_TX_ENABLE;
}

void dma_spi_rx(uint8_t * data, uint16_t size) {

	RCC->AHBENR |= RCC_AHBENR_DMA1EN;

	DMA1_Channel2->CPAR 	= (uint32_t) & SPI1->DR;
	DMA1_Channel2->CMAR 	= (uint32_t) data;
	DMA1_Channel2->CNDTR 	= size;

	DMA1_Channel2->CCR = DMA_CCR2_PL_0 | DMA_CCR2_MINC | DMA_CCR2_TCIE;

    SPI1->CR2 |= SPI_CR2_RXDMAEN;

    NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}

void SPI_ReciveData(uint8_t *data, uint8_t size) {
	dma_spi_rx(data, size);
    AD7195_CS_LOW;

    DMA_SPI_RX_ENABLE;
}




int main(void){
	uint8_t spi_data[]={0x60};

	__enable_irq ();

	GPIO_INIT();
	SPI_INIT();

	for( uint8_t byte = 0; byte <6; byte++ ){
		while (!(SPI1->SR & SPI_SR_TXE));
		SPI1->DR = 0xFF;
	}

	while ( SPI1->SR & SPI_SR_BSY );

	for(uint32_t i=0; i<72000; i++);

	SPI_SendData(spi_data, 1);


    while(1){
    }
}

void DMA1_Channel3_IRQHandler(void) {
    if (DMA1->ISR & DMA_ISR_TCIF3) {
    	while ( SPI1->SR & SPI_SR_BSY );

    	AD7195_CS_HIGH;

    	DMA_SPI_TX_DISABLE;
    	SPI1->CR2 |= SPI_CR2_TXDMAEN;

    	SPI_ReciveData(get, 1);
    	while (!(SPI1->SR & SPI_SR_TXE));
    	SPI1->DR = 0x00;

    	DMA1->IFCR = DMA_IFCR_CTCIF3;
    }

  }

void DMA1_Channel2_IRQHandler(void) {
    if (DMA1->ISR & DMA_ISR_TCIF2) {
    	while ( SPI1->SR & SPI_SR_BSY );
    	AD7195_CS_HIGH;
    	GPIOA->BSRR  |=   GPIO_BSRR_BS12;
    	GlobalVar_SPI_Received = 1;

    	DMA_SPI_RX_DISABLE;
    	DMA1->IFCR = DMA_IFCR_CTCIF2;
    }
  }

Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение dosikus »

[uquote="Alex-Elektron",url="/forum/viewtopic.php?p=3227120#p3227120"]Столкнулся с магией: написал всю эту либилерду в КОКОСЕ и она заработала!!! В Кейле же прерываний как не было так и нет! За что меня так наказали?[/uquote]

Стартап подключен?
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

dosikus, в точку! Большое спасибо!
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

Прошу помощи! Всё тот же DMA. Работает в связке с SPI 2. Причём данные передаёт прекрасно, со свистом. Но прерывание по приёму не работает. Стартап подключен. Настройки периферии:
1. GPIO

Код: Выделить всё

void spi2_gpio_init(void){
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;

    //------- CS_OLED, RESET_OLED, POWER_OLED, D/C#_OLED -----------------------------------
    GPIOB->CRH   |=  (GPIO_CRH_MODE12 | GPIO_CRH_MODE11 | GPIO_CRH_MODE10);  // Выход, 50 МГц
    GPIOB->CRH   &= ~(GPIO_CRH_CNF12  | GPIO_CRH_CNF11  | GPIO_CRH_CNF10);    	// Общего назначения, push-pull

    GPIOB->CRL   |=  GPIO_CRL_MODE2;   	// Выход, 50 МГц
    GPIOB->CRL   &= ~GPIO_CRL_CNF2;     	// Общего назначения, push-pull

    GPIOB->BSRR   =  GPIO_BSRR_BS12;     	// Высокий уровень
    //--------------------------------------------------------------------------------------

    //--- CS_FLASH, CS_EEPROM --------------------------------------------------------------
    GPIOC->CRL   |=  (GPIO_CRL_MODE5 | GPIO_CRL_MODE4);   	// Выход, 50 МГц
    GPIOC->CRL   &= ~(GPIO_CRL_CNF5  | GPIO_CRL_CNF4);     	// Общего назначения, push-pull

    GPIOC->BSRR   =  GPIO_BSRR_BS5 | GPIO_BSRR_BS4;     	// Высокий уровень
    //--------------------------------------------------------------------------------------

    //--- SCK, MOSI --------------------------------------
    GPIOB->CRH   |=  (GPIO_CRH_MODE13  | GPIO_CRH_MODE15);    	// Выход, 50 МГц
    GPIOB->CRH   &= ~(GPIO_CRH_CNF13   | GPIO_CRH_CNF15);
    GPIOB->CRH   |=  (GPIO_CRH_CNF13_1 | GPIO_CRH_CNF15_1);   	// Альтернативная функция, push-pull
    //----------------------------------------------------

    //------- MISO-PIN ----------------
    GPIOB->CRH   &= ~GPIO_CRH_MODE14;	// Вход
    GPIOB->CRH   &= ~GPIO_CRH_CNF14;
    GPIOB->CRH   |=  GPIO_CRH_CNF14_0;   	// floating
    //---------------------------------
2. SPI2

Код: Выделить всё

/*
* 2-line unidirectional data mode
* CRC disabled
* 8bit data format
* Full duplex
* Software slave management enabled
* MSB transmitted first
* fPCLK/2
* Master configuration
* SCK to 1 when idle
* The second clock transition is the first data capture edge
*/
void spi_init(void){

    RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
    
    SPI2->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_BR_0 | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA | SPI_CR1_SPE;

    GPIOB->BSRR   =  GPIO_BSRR_BS13;  //SCK pull-up
}
3. DMA_TX

Код: Выделить всё

void dma_spi2_tx(uint8_t *data, uint16_t size) {
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;                   

    DMA1_Channel5->CCR = 0;
    
    DMA1_Channel5->CPAR = (uint32_t) &SPI2->DR;         //Указываем адрес периферии
    DMA1_Channel5->CMAR = (uint32_t) &data[0];              //Указываем адрес в памяти

    DMA1_Channel5->CNDTR = size;                        //Количество пересылаемых значений

    DMA1_Channel5->CCR = DMA_CCR5_DIR   | //Указываем направление передачи данных, из памяти в периферию
                                          DMA_CCR5_MINC | //Адрес памяти инкрементируем после каждой пересылки.
                                          DMA_CCR5_PL      | //Приоритет - очень высокий
                                          DMA_CCR5_TCIE   | //Разрешаем прерывание по окончанию передачи
                                          DMA_CCR5_EN;    //Разрешаем работу 4-го канала DMA

	
    SPI2->CR2 = SPI_CR2_TXDMAEN;
    
    NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}
4. DMA_RX

Код: Выделить всё

void dma_spi2_rx(uint8_t *data, uint16_t size) {
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;   
    DMA1_Channel4->CCR = 0;    

    DMA1_Channel4->CPAR = (uint32_t) &SPI2->DR;         //Указываем адрес периферии
    DMA1_Channel4->CMAR = (uint32_t) &data[0];              //Указываем адрес в памяти

    DMA1_Channel4->CNDTR = size;                        //Количество пересылаемых значений

    DMA1_Channel4->CCR = DMA_CCR4_MINC | //Адрес памяти инкрементируем после каждой пересылки.
                                          DMA_CCR4_PL   | //Приоритет - очень высокий
                                          DMA_CCR4_HTIE | //Разрешаем прерывание по передаче половины буфера
                                          DMA_CCR4_TCIE | //Разрешаем прерывание по окончанию передачи
                                          DMA_CCR4_TEIE | //Разрешаем прерывание по окончанию передачи
                                          DMA_CCR4_EN;    //Разрешаем работу 4-го канала DMA

	
    SPI2->CR2 = SPI_CR2_RXDMAEN;
    
    NVIC_EnableIRQ(DMA1_Channel4_IRQn);
}
5. Приём/отправка данных

Код: Выделить всё

void SPI_SendData(uint8_t *data, uint16_t size) {
    dma_spi2_tx(data, size);
}
 
void SPI_ReciveData(uint8_t *data, uint16_t size) {
    dma_spi2_rx(data, size);
    SPI_SendData(data, size);
}
6. Обработчик прерываний по окончанию передачи

Код: Выделить всё

void DMA1_Channel5_IRQHandler() {
    if (DMA1->ISR & DMA_ISR_TCIF5 ) {
      
      while(!(SPI2->SR & SPI_SR_TXE));
      while (SPI2->SR & SPI_SR_BSY); 
        
      All_Modules_Deselect();
         
      DMA1_Channel5->CCR &= ~DMA_CCR5_EN;  
      SPI2->CR2 &= ~ SPI_CR2_TXDMAEN;

      DMA1->IFCR |= DMA_IFCR_CTCIF5; 
    }
 }
7. Обработчик прерываний по окончанию приёма

Код: Выделить всё

void DMA1_Channel4_IRQHandler(void) {
   if (DMA1->ISR & DMA_ISR_HTIF4 ) {
 
      // Уведомляем, что данные приняты
     GlobalVar_SPI_Received = 1; 
  
     DMA1_Channel4->CCR &= ~DMA_CCR4_EN;  
     DMA1->IFCR |= DMA_IFCR_CHTIF4; 
    }
  
   if (DMA1->ISR & DMA_ISR_TCIF4 ) {
 
      // Уведомляем, что данные приняты
     GlobalVar_SPI_Received = 1; 

     DMA1_Channel4->CCR &= ~DMA_CCR4_EN;  
     DMA1->IFCR |= DMA_IFCR_CTCIF4; 
    }

   if (DMA1->ISR & DMA_ISR_TEIF4 ) {
 
      // Уведомляем, что данные приняты
     GlobalVar_SPI_Received = 1; 
 
     DMA1_Channel4->CCR &= ~DMA_CCR4_EN;  
     DMA1->IFCR |= DMA_IFCR_CTEIF4; 
    }
}
Проверку приёма делаю по переменной GlobalVar_SPI_Received. Если она =1, то выкидываем принятые данные в USART. Но прикол в том, что МК не входит в прерывание void DMA1_Channel4_IRQHandler(void). Чего здесь не хватает? По логам ответ от внешнего флеша идёт, запрашиваю 512 байт - он их выкидывает.
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение dosikus »

Код: Выделить всё

DMA1->IFCR = DMA_IFCR_CHTIF4;
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

Не, не помогло. Перенёс передачу по USART прямо в прерывание - ноль реакции. Он даже не заходит в прерывание.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Reflector »

[uquote="Alex-Elektron",url="/forum/viewtopic.php?p=3476711#p3476711"]5. Приём/отправка данных

Код: Выделить всё

void SPI_SendData(uint8_t *data, uint16_t size) {
    dma_spi2_tx(data, size);   // SPI2->CR2 = SPI_CR2_TXDMAEN;
}

void SPI_ReciveData(uint8_t *data, uint16_t size) {
    dma_spi2_rx(data, size);   // SPI2->CR2 = SPI_CR2_RXDMAEN;
    SPI_SendData(data, size);
}
[/uquote]
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

Тоже мимо(
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Reflector »

[uquote="Alex-Elektron",url="/forum/viewtopic.php?p=3476769#p3476769"]Тоже мимо([/uquote]
Не мимо, просто помимо этой ошибки есть и другие :)
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

На передачу не влияет точно порядок, сперва dma или spi было включено
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Reflector »

[uquote="Alex-Elektron",url="/forum/viewtopic.php?p=3476787#p3476787"]На передачу не влияет точно порядок, сперва dma или spi было включено[/uquote]
При чем тут порядок, у тебя вызов SPI_SendData() сбрасывает SPI_CR2_RXDMAEN.
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение dosikus »

Приоритеты прерываний выстави...
Аватара пользователя
AlanDrakes
Прорезались зубы
Сообщения: 236
Зарегистрирован: Пн июл 04, 2016 16:51:22
Откуда: Россия, Омск

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение AlanDrakes »

У меня аналогично не работает корректно приём данных посредством DMA. Из того, что удалось выяснить во время отладки - SPI модуль ЖДЁТ, пока в SPI->TDR будут положены новые данные.
При приёме можете попробовать инициализировать DMA1_Channel5, но без смещения адреса буфера (например постоянно читать байт в котором будет 0xFF или ноль), после этого настроить Channel4 и разрешить их работу.
У меня в коде аналогичный костыль.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Reflector »

[uquote="AlanDrakes",url="/forum/viewtopic.php?p=3476979#p3476979"]УИз того, что удалось выяснить во время отладки - SPI модуль ЖДЁТ, пока в SPI->TDR будут положены новые данные.[/uquote]
Что же тут удивительного?
In reception, a DMA request is issued each time RXNE is set to 1. The DMA then reads the SPI_DR register (this clears the RXNE flag).
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

!!!
При чем тут порядок, у тебя вызов SPI_SendData() сбрасывает SPI_CR2_RXDMAEN.
!!! :facepalm:

Всё пошло, поехало! Спасибо!
Frogfot
Мучитель микросхем
Сообщения: 443
Зарегистрирован: Ср окт 19, 2011 08:48:27
Откуда: Мать городов русских

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Frogfot »

Короче, наступил на свои грабли - запустил на F103 SPI + DMA - 1 раз входит в прерывание от DMA и всё :(

Код: Выделить всё

void Init_DMA5 (void) // SPI2 Transmitte
{
  RCC->AHBENR |= RCC_AHBENR_DMA1EN;                       // Enable Clock DMA1
  DMA1_Channel5->CCR   = 0x0000;                                    // Disable DMA
  DMA1_Channel5->CPAR  = (uint32_t)&(SPI2->DR);                     // Periferal Adress
  DMA1_Channel5->CMAR  = (uint32_t)&(ScreenBuf [(AdressLED << 4)]); // Memory Adress
  DMA1_Channel5->CNDTR = DMA_BUFF_SIZE;                              // Number of data to transfer
  DMA1_Channel5->CCR   = DMA_CCR1_DIR  |   // Data transfer direction - Read from memory
                         DMA_CCR1_MINC |   // Memory increment mode enabled
                         DMA_CCR1_TCIE   | // Transfer complete interrupt enable
                         DMA_CCR1_EN;      // Enable DMA1

  SPI2->CR2           |= SPI_CR2_TXDMAEN; // Tx buffer DMA enabled

  NVIC_EnableIRQ(DMA1_Channel5_IRQn); // Enable Interrupt DMA1 channel CH5 in NVIC
	
  NVIC_SetPriority(DMA1_Channel5_IRQn,14);
}

Код: Выделить всё

void DMA1_Channel5_IRQnHandler (void)
{
  static u16 CntDMA1CH5;
  if (CntDMA1CH5++ & 0x00F0) { GPIOA->BSRR = GPIO_BSRR_BR12; } // PA12 - LED RED
  else                                      { GPIOA->BSRR = GPIO_BSRR_BS12; }
  while (!(SPI2->SR & SPI_SR_TXE));
  while   (SPI2->SR & SPI_SR_BSY);
  if (DMA1->ISR & DMA_ISR_TCIF5)   // Check Transfer Complete flag
  {
  	DMA1->IFCR |= DMA_IFCR_CTCIF5; // Clear Transfer Complete flag
  }
 DMA1->IFCR |= DMA_IFCR_CGIF5;        // Channel 5 Global interrupt clear
}
Хорошему коту и в декабре - март :)
Alex-Elektron
Встал на лапы
Сообщения: 113
Зарегистрирован: Сб янв 11, 2014 21:25:55

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Alex-Elektron »

А Вы DMA перезапускаете после срабатывания прерывания? Хочется увидеть функцию передачи
Frogfot
Мучитель микросхем
Сообщения: 443
Зарегистрирован: Ср окт 19, 2011 08:48:27
Откуда: Мать городов русских

Re: DMA+SPI+STM32f103. Трабл с прерыванием.

Сообщение Frogfot »

[uquote="Alex-Elektron",url="/forum/viewtopic.php?p=3621149#p3621149"]А Вы DMA перезапускаете после срабатывания прерывания? Хочется увидеть функцию передачи[/uquote]

Код: Выделить всё

// -----------------------------------------------------------------------------
void ReStart_DMA5 (void) // SPI2 Transmitte
{
  DMA1_Channel5->CCR  &= ~DMA_CCR1_EN;                               // Disable DMA
  DMA1_Channel5->CPAR  = (uint32_t) &(SPI2->DR);                     // Periferal Adress
  DMA1_Channel5->CMAR  = (uint32_t) &(ScreenBuf [(AdressLED << 4)]); // Memory Adress
  DMA1_Channel5->CNDTR = DMA_BUFF_SIZE;                              // Number of data to transfer
  DMA1_Channel5->CCR  |= DMA_CCR1_EN;                                // Enable DMA
}
Хорошему коту и в декабре - март :)
Ответить

Вернуться в «ARM»