Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

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

Чт ноя 02, 2017 14:06:52

Доброго. Настраиваю связку 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;
   }
      
}

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

Пт ноя 03, 2017 10:39:25

Я увидел ошибку конфигурации 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.

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

Ср ноя 08, 2017 13:57:50

Да, безусловно. Там должно было быть
Код:
 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;
    }
  }

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

Чт ноя 09, 2017 07:28:48

Столкнулся с магией: написал всю эту либилерду в КОКОСЕ и она заработала!!! В Кейле же прерываний как не было так и нет! За что меня так наказали?


Стартап подключен?

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

Пн ноя 13, 2017 06:50:07

dosikus, в точку! Большое спасибо!

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

Вт окт 09, 2018 12:27:27

Прошу помощи! Всё тот же 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 байт - он их выкидывает.

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

Вт окт 09, 2018 12:51:02

Код:
DMA1->IFCR = DMA_IFCR_CHTIF4;

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

Вт окт 09, 2018 13:06:22

Не, не помогло. Перенёс передачу по USART прямо в прерывание - ноль реакции. Он даже не заходит в прерывание.

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

Вт окт 09, 2018 13:43:25

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);
}

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

Вт окт 09, 2018 13:47:07

Тоже мимо(

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

Вт окт 09, 2018 13:50:00

Тоже мимо(

Не мимо, просто помимо этой ошибки есть и другие :)

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

Вт окт 09, 2018 14:06:33

На передачу не влияет точно порядок, сперва dma или spi было включено

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

Вт окт 09, 2018 14:11:24

На передачу не влияет точно порядок, сперва dma или spi было включено

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

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

Вт окт 09, 2018 15:35:49

Приоритеты прерываний выстави...

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

Вт окт 09, 2018 18:14:32

У меня аналогично не работает корректно приём данных посредством DMA. Из того, что удалось выяснить во время отладки - SPI модуль ЖДЁТ, пока в SPI->TDR будут положены новые данные.
При приёме можете попробовать инициализировать DMA1_Channel5, но без смещения адреса буфера (например постоянно читать байт в котором будет 0xFF или ноль), после этого настроить Channel4 и разрешить их работу.
У меня в коде аналогичный костыль.

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

Вт окт 09, 2018 19:07:03

УИз того, что удалось выяснить во время отладки - SPI модуль ЖДЁТ, пока в SPI->TDR будут положены новые данные.

Что же тут удивительного?
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).

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

Ср окт 10, 2018 06:25:36

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

Всё пошло, поехало! Спасибо!

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

Вс апр 21, 2019 19:43:49

Короче, наступил на свои грабли - запустил на 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
}

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

Пн апр 22, 2019 13:43:04

А Вы DMA перезапускаете после срабатывания прерывания? Хочется увидеть функцию передачи

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

Пн апр 22, 2019 16:15:35

А Вы DMA перезапускаете после срабатывания прерывания? Хочется увидеть функцию передачи

Код:
// ----------
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
}
Ответить