2016-08-04 6 views
0

나는 STM32f405를 가지고 있으며, 그 작업은 SPI를 통해 데이터를 전송하고 DMA로 프로세서 시간을 절약하는 것이다. 사용 된 SPI는 핀 PA4 ~ PA7이있는 SPI1입니다. DMA에 대해 DMA2 채널 3에서 3 번째 스트림을 선택했습니다. 아이디어는 CS 신호를 활성화하고 메모리에 일부 데이터를 저장 한 다음 DMA에 의해 자동으로 전송되고 일단 완료되면 DMA가 인터럽트를 트리거해야합니다 핸들러를 사용하여 CS를 비활성화합니다. 다음은 코드입니다.DMA로 데이터를 전송하기 위해 STM32f405 SPI를 구성하는 방법은 무엇입니까?

static void SPI_Config(void) { 
    GPIO_InitTypeDef GPIO_InitStructure; 
    SPI_InitTypeDef SPI_InitStructure; 
    DMA_InitTypeDef DMA_Init_Structure; 
    NVIC_InitTypeDef NVIC_InitStructure; 
    /* Enable the SPI clock */ 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); 
    /* Enable GPIO clocks */ 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 
    /* Enable DMA clock */ 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 
    /* SPI GPIO Configuration --------------------------------------------------*/ 
    /* GPIO Deinitialisation */ 
    GPIO_DeInit(GPIOA); 
    /* Connect SPI pins to AF5 */ 
// GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); //SS 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); //SCK 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); //MISO 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); //MOSI 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //SCK 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MISO 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //MOSI 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //SS 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    //DMA Globul Interrupt 
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure); 

    //DMA Configuration 
    DMA_DeInit(DMA2_Stream3); 
    DMA_Cmd(DMA2_Stream3, DISABLE); 
    while (DMA1_Stream0->CR & DMA_SxCR_EN); 
    DMA_Init_Structure.DMA_BufferSize = 0; 
    DMA_Init_Structure.DMA_Channel = DMA_Channel_3; 
    DMA_Init_Structure.DMA_DIR = DMA_DIR_MemoryToPeripheral; 
    DMA_Init_Structure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
    DMA_Init_Structure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; 
    DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_tx_val); 
    DMA_Init_Structure.DMA_MemoryBurst = DMA_MemoryBurst_Single; 
    DMA_Init_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    DMA_Init_Structure.DMA_MemoryInc = DMA_MemoryInc_Disable; 
    DMA_Init_Structure.DMA_Mode = DMA_Mode_Circular; 
    DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR)); 
    DMA_Init_Structure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    DMA_Init_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    DMA_Init_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    DMA_Init_Structure.DMA_Priority = DMA_Priority_High; 
    DMA_Init(DMA2_Stream3,&DMA_Init_Structure); 

    //SPI Configuration 
    SPI_I2S_DeInit(SPI1); 
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; 
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; 
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //AD5620 doku page 18 falling edge of SCLK 
    SPI_InitStructure.SPI_CRCPolynomial = 0; //x_8+x_2+x_1+1 in python hex(2**8+2**2+2+1) 
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //AD5620 input register is 16 bit 
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; 
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 
    SPI_Init(SPI1, &SPI_InitStructure); 




} 

int8_t Analog_Out_Config(uint32_t target_reg_val) { 
    uint16_t power_on_status; 
    target_reg_val = target_reg_val; 
    SPI_Config(); 
// SPI_Cmd(SPI1, ENABLE); 
// power_on_status=PowerOn_AD5750_OutDriver(); 
// if(power_on_status) { 
     //enable dma interrupt 
//  SPI_Cmd(SPI1, DISABLE); 
     DMA_ITConfig(DMA2_Stream3,DMA_IT_TC,ENABLE); 
     DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3|DMA_FLAG_DMEIF3|DMA_FLAG_TEIF3|DMA_FLAG_HTIF3|DMA_FLAG_TCIF3); 
     DMA_Cmd(DMA2_Stream3, ENABLE); 
     SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx, ENABLE); 
     SPI_Cmd(SPI1, ENABLE); 

     return power_on_status&0x07; 
// }else { 
//  return -1; 
// } 
} 
void Analog_Output(uint32_t measured_reg_val) { 
    val=0x7ff; 
    ACTIVATE_CS_DAC(); 
    spi_tx_val=val; 
} 

void DMA2_Stream3_IRQHandler(void) { 
    if(DMA_GetITStatus(DMA2_Stream3,DMA_IT_TCIF3)!=RESET) { 
     DMA_ClearITPendingBit(DMA2_Stream3,DMA_IT_TCIF0|DMA_IT_HTIF0); 
     DEACTIVATE_CS_DAC(); 

    } 
} 

int main(void) 
{ 
    target_reg_val=14; 
    measured_reg_val=12; 
    Analog_Out_Config(target_reg_val); 
    while (1) 
    { 
     for(val=-target_reg_val;val<target_reg_val;val++) { 
      Analog_Output(val); 
      for(i=0;i<1000;i++); 
     } 

    } 
} 

디버거를 사용하여 DMA2_Stream3_IRQHandler가 활성화되지 않았다는 것을 알았습니다. 참조 설명서에 따르면 DMA는 SPI_DR 레지스터의 TXE 플래그가 1 일 때 데이터를 전송해야합니다. 또한 SPI_CR2에서 TXDMAEN 플래그가 설정되었습니다. DMA S3CR 레지스터도 체크했는데 플래그 TCIE와 EN도 설정되었습니다. 또한 DMA2_Stream3_IRQHandler 함수가 main 함수에서 볼 수 있습니다. 여전히 DMA2_Stream3_IRQHandler는 활성화되지 않았습니다.

업데이트 : 수동으로 DMA2_S3CR 레지스터의 EN 비트를 재설정하면 DMA2_Stream3_IRQHandler가 트리거됩니다. 참조 매뉴얼에 따라서이 비트를 하드웨어에 의해 클리어된다 : 전송 오류 AHB 마스터 버스 발생하면

  • 전송하는 DMA 단부에
  • 을 (설정할 준비 스트림)
  • 메모리 AHB 포트 FIFO 임계 값이 나는 또한 SPI_Config과 Analog_Out_Config을 변경 한 버스트

의 크기와 호환되지 않습니다 만, 여전히 디버거 DMA2_Stream3_IRQHandler의 중재가 트리거되지 않습니다 않고. DMA가 전송을 트리거하지 않고 어떤 이유로 종료 할 수없는 것 같습니다. DMA가 전송을 트리거하는지 어떻게 알 수 있습니까?

+0

TL; DR 그러나 실제 전송이 시작되기 전에 DMA가 주변 장치에서 활성화되어야합니다. 한 가지 측면은 CPU와 DMA 전송을 (쉽게) 혼합 할 수 없다는 것입니다. (예 : USART에서도 마찬가지입니다.) – Olaf

+0

여기에 모든 코드를 넣지 않았다고 가정하고 있지만, 질문에서 DMA를 설정하는 곳에서'SPI_Config'를 호출하지 않습니다. 실제로 이것이 사실이라면 그것이 아마도 작동하지 않는 이유 일 것입니다. – rjp

+0

@rjp SPI 전송 전용 DMA를 포함하여 SPI를 설정하기 위해 SPI_Config를 사용하고 있습니다. 하지만 Analog_Out_Config 기능으로 DMA를 사용할 수 있습니다. 이전에 ADC와 같은 시스템의 다른 부분을 위해이 작업을 해왔습니다. –

답변

0

DMA 구성 구조가 DMA_Mode에서 DMA_NORMAL으로 설정되어 있습니다. 주변 흐름 제어 인 DMA_PFCTRL으로 설정해야합니다. 이렇게하면 DMA가 계속 실행되지 않고 주변 장치 (구성한 장치)의 신호를 기다리게됩니다. 하지만이 설정이 없다면 SPI_DR은 DMA 전송의 모든 메모리 설정을 연속적으로 덤프해야하므로 (첫 번째 단어를 이동하는 것처럼) SPI 버스에서 하나 또는 두 개의 단어가 나올 것으로 예상됩니다. .

확인해야 할 또 다른 사항은 주변기기 (SPI1, DMA2)가 재설정되어 있지 않다는 것입니다. 나는 당신이 시계를 무력화 한 ㄴ다는 것을 본다, 그러나 ST가 또한 그 외침에 재설정의 주변 장치를 가지고가는 경우에 나는 생각하지 않는다.

참고 : 참고로 STM32F2xx DMA 주변 장치를 사용했지만 STM32F4xx 주변 장치는 수퍼 세트 인 경향이 있습니다. 또한 내가 참조로 사용한 것과 다른 버전의 ST 주변 장치 라이브러리를 사용하고있는 것처럼 보입니다.

+0

F4 주변 장치는 실제로 F2 주변 장치와 동일합니다 (일부는 그렇지 않았 으면합니다 ...). 추가 참고 사항 : 쓰레기 STlib 사용을 강력히 거부합니다. 그것은 단지 bloatware이며 불필요하게 것들을 복잡하게합니다. 그것을 "HAL"이라고 명명하는 것은 단순한 농담입니다. 어쨌든 하드웨어를 알아야합니다. 주변 장치 정의 헤더를 사용하고 하드웨어 액세스를 캡슐화하기 위해 자체 드라이버를 작성하십시오. – Olaf

+0

그것이 몇 년이 지났지 만 우리가 그 일을 끝내 었습니다. 필자는 Kinetis 제품군으로 옮겼습니다. Kinetix 제품군에는 실제로 사용 가능한 드라이버가 몇 개 있습니다 (Kinetis 주변 장치에 대한 포트를 포팅 한 휴대용 프레임 워크가 몇 개 있지만). – rjp

+0

@ 두 가족 모두 실제로 프로그래밍되었습니다. 그래도 직접 하드웨어 액세스가 가능한 드라이버와 일치하는 라이브러리를 표시해야합니다. 한가지 중요한 문제는이 라이브러리가 종종 내가 선호하는 것과 일치하지 않는 시스템 아키텍처를 시행한다는 것입니다 (다양한 프로젝트에서 우수성을 입증했습니다). 이러한 라이브러리는 특히 인터럽트 우선 순위, 매우 영리한 멀티 스레딩 지원 등을 제공하는 Cortex-M3/4/7에서 오래된 프로그래밍 스타일을 고수하는 경향이 있습니다. 아마도. 그러나 나는 그들에게 좋은 이유가있다. – Olaf