2015년 12월 25일 금요일

stm32 SPI 예제

#include "stm32f10x.h" //헤더

typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus; //상태 enum
#define SPI2_DR_Address  0x4000380C //spi2 주소
#define BufferSize       32 //버퍼 사이즈
SPI_InitTypeDef  SPI_InitStructure; //spi 구조체
DMA_InitTypeDef  DMA_InitStructure; //DMA 구조체
GPIO_InitTypeDef GPIO_InitStructure; //GPIO 설정 구조체
uint8_t SPI1_Buffer_Tx[BufferSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                                 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
                                 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
                                 0x1C, 0x1D, 0x1E, 0x1F, 0x20}; //spi1 전송 TX 버퍼
uint8_t SPI2_Buffer_Rx[BufferSize]; //수신 버퍼
uint8_t TxIdx = 0; //아이디
volatile TestStatus TransferStatus = FAILED; //상태 (하드웨어 변경 가능)
void RCC_Configuration(void); //클럭 설정
void GPIO_Configuration(void);//gpio 설정
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength); //두개 버퍼 비교후 true false
                
 int main(void)
{
  RCC_Configuration();//클럭 설정
  GPIO_Configuration();//GPIO설정
  /* DMA1 channel4 configuration ---------------------------------------------*/
  DMA_DeInit(DMA1_Channel4);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPI2_DR_Address;//실제 SPI 칩의 주소 어떤 정보를 받을지 설정
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI2_Buffer_Rx;// 실제 저장될 메모리 주소
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//?
  DMA_InitStructure.DMA_BufferSize = BufferSize;//변수에 저장할 메모리 크기 설정
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//미사용
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//메모리 주소를 증가시키면서 다음메모리 정보 사용
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//바이트
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//변수에 저장할 데이타크기 바이트로 설정
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//보통모드
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//우선순위
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//?
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);//저장
  /* SPI1 configuration ------------------------------------------------------*/
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //단방향 양방향 결정가능
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //마스터모드
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8비트 모드
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//CPOL 는 리셋 극성 변경 가능
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//CPHA 는 셋 마스터 클럭의 rising,falling edge 할건지  결정 가능
  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; //nss 하드웨어 소프트웨어 셜정가능
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //18MHZ
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB first
  SPI_InitStructure.SPI_CRCPolynomial = 7;//?
  SPI_Init(SPI1, &SPI_InitStructure);//설정완료
  /* SPI2 configuration ------------------------------------------------------*/
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Rx; //단방향
  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;//슬레이브모드
  SPI_Init(SPI2, &SPI_InitStructure);//설정완료

  SPI_SSOutputCmd(SPI1, ENABLE);//아웃풋을 받을거라 설정
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE); //Tx 도 설정 이 가능하지만 spi2의 RX 사용으로 설정함
  SPI_Cmd(SPI2, ENABLE);//슬레이브 사용
  SPI_Cmd(SPI1, ENABLE);//마스터 사용
  DMA_Cmd(DMA1_Channel4, ENABLE);//DMA 채널 14 사용

  while (TxIdx < BufferSize) //TX갯수가 버퍼 사이즈보다 작으면 반복
  {
   
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //마스터의 spi i2s 상태가 리셋이면 계속 spt1 버퍼에 데이터를 저장한다.
  
    SPI_I2S_SendData(SPI1, SPI1_Buffer_Tx[TxIdx++]);
  }//데이터를 보내기 위해 spi1의 버퍼 데이터를 DMA에 저장

  while (!DMA_GetFlagStatus(DMA1_FLAG_TC4));//데이터가 다 보내질 때 가지 기다림
 
  TransferStatus = Buffercmp(SPI2_Buffer_Rx, SPI1_Buffer_Tx, BufferSize); //송신된 버퍼와 수신된 버퍼를 비교한다.
 while (TransferStatus==PASSED)
  {

  GPIOC->BSRR=GPIO_Pin_9;

 }
 
}               
                
void RCC_Configuration(void)
{
 
  SystemInit();//시스템 이닛

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA1 클럭을 사용한다.
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_SPI1, ENABLE);//72mhz A B SPI1 클럭을 사용
 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//36mhz SPI2 클럭을 사용
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

}
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /* Configure SPI1 pins: NSS, SCK, MISO and MOSI ----------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50mHZ
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //대체 펑션 모드로 설정
  GPIO_Init(GPIOA, &GPIO_InitStructure);//SPI1->A 설정
  /* Configure SPI2 pins: NSS, SCK, MISO and MOSI ----------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_Init(GPIOB, &GPIO_InitStructure);//SPI2-> B설정 위와 동일

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

}
                
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)//두개 버퍼 비교후 true false
{
  while (BufferLength--)
  {
    if (*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }
    pBuffer1++;
    pBuffer2++;
  }
  return PASSED;
}
#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t* file, uint32_t line)
{
  while (1)
  {}
}
#endif

댓글 없음:

댓글 쓰기