초보의 아웅다웅 설계하기/STM32

STM32L4 SPI LL_DRIVER

로망와니 2019. 5. 25. 07:52

 

#include "string.h"

#include "usr_system.h"

#include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_spi.h"
#include "stm32l4xx_ll_dma.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

#define SPI_1  1 

#define SPI_2  2
#define SPI_3 3
#define SPI_4 4
#define SPI_5 5

#define SPI_MASTER LL_SPI_MODE_MASTER
#define SPI_SLAVE  LL_SPI_MODE_SLAVE

#define SPI1_NSS_PORT GPIOB
#define SPI1_NSS_PIN LL_GPIO_PIN_6
#define SPI1_SCK_PORT GPIOA
#define SPI1_SCK_PIN LL_GPIO_PIN_5
#define SPI1_MISO_PORT GPIOA
#define SPI1_MISO_PIN LL_GPIO_PIN_6
#define SPI1_MOSI_PORT GPIOA
#define SPI1_MOSI_PIN LL_GPIO_PIN_7

/* Defines -------------------------------------------------------------------*/
#define DUMMY_BYTE    0x00
#define SPI_FLAG_TIMEOUT 0x1000;
#define SPI_RXFLAG_TIMEOUT 0x1000;

#define SPIRBUF_SIZE       128


/* Private macro ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
tSpi Spi1;

/* Private function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void Init_SPI(uint8_t a_chSpi, uint32_t a_nMasterSlave, const InterruptEnableState a_chInt, const InterruptEnableState a_chDMA);
static void ClearBuf_SPI1(void);

/*******************************************************************************
* Function Name : 
* Parameters    : None
* Return        : None
* Description   : 
*******************************************************************************/
void Config_SPI(void)
{
Init_SPI(SPI_1, SPI_MASTER, eInterruptDisable, eInterruptDisable);
}

/*******************************************************************************
* Function Name : SPI_Init(uint8_t a_chSpi, uint32_t a_nMasterSlave)
* Description   :SPI 초기화, 반이중 방식일 경우 MOSI와 MISO를 크로스 해주어야 함.
* Parameters    : 통신포트. 마스터 슬레이브
* Return        : None
*******************************************************************************/
static void Init_SPI(uint8_t a_chSpi, uint32_t a_nMasterSlave, const InterruptEnableState a_chInt, const InterruptEnableState a_chDMA)

  if(a_chSpi == 1)
  {
/* (1) Enables GPIO clock and configures the SPI1 pins ********************/
/* Enable the peripheral clock of GPIOA */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
/* Enable the peripheral clock of GPIOB */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

/* Configure SCK Pin connected to pin 31 of CN12 connector */
LL_GPIO_SetPinMode(SPI1_SCK_PORT, SPI1_SCK_PIN, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(SPI1_SCK_PORT, SPI1_SCK_PIN, LL_GPIO_AF_5);
LL_GPIO_SetPinSpeed(SPI1_SCK_PORT, SPI1_SCK_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinPull(SPI1_SCK_PORT, SPI1_SCK_PIN, GPIO_NOPULL);//LL_GPIO_PULL_DOWN

/* Configure MISO Pin connected to pin 27 of CN12 connector */
LL_GPIO_SetPinMode(SPI1_MISO_PORT, SPI1_MISO_PIN, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(SPI1_MISO_PORT, SPI1_MISO_PIN, LL_GPIO_AF_5);
LL_GPIO_SetPinSpeed(SPI1_MISO_PORT, SPI1_MISO_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinPull(SPI1_MISO_PORT, SPI1_MISO_PIN, GPIO_NOPULL);//LL_GPIO_PULL_DOWN

/* Configure MOSI Pin connected to pin 29 of CN12 connector */
LL_GPIO_SetPinMode(SPI1_MOSI_PORT, SPI1_MOSI_PIN, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(SPI1_MOSI_PORT, SPI1_MOSI_PIN, LL_GPIO_AF_5);
LL_GPIO_SetPinSpeed(SPI1_MOSI_PORT, SPI1_MOSI_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinPull(SPI1_MOSI_PORT, SPI1_MOSI_PIN, GPIO_NOPULL);//LL_GPIO_PULL_DOWN

/* (3) Configure SPI1 functional parameters ********************************/

/* Enable the peripheral clock of GPIOA */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

LL_SPI_SetStandard(SPI1, 0x00);
LL_SPI_SetClockPhase(SPI1, LL_SPI_PHASE_2EDGE);
LL_SPI_SetClockPolarity(SPI1, LL_SPI_POLARITY_LOW);
LL_SPI_SetBaudRatePrescaler(SPI1, LL_SPI_BAUDRATEPRESCALER_DIV16);
LL_SPI_SetTransferBitOrder(SPI1, LL_SPI_MSB_FIRST);
LL_SPI_SetTransferDirection(SPI1, LL_SPI_FULL_DUPLEX);
LL_SPI_SetDataWidth(SPI1, LL_SPI_DATAWIDTH_8BIT);
LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER);

LL_SPI_SetCRCWidth(SPI1, 0x00);
LL_SPI_SetCRCPolynomial(SPI1, 7);
LL_SPI_DisableCRC(SPI1);
LL_SPI_DisableNSSPulseMgt(SPI1);
if(a_nMasterSlave == SPI_MASTER){
/* Configure CE Pin connected to pin 29 of CN10 connector */
LL_GPIO_SetPinMode(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinPull(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_PULL_NO);

LL_SPI_SetNSSMode(SPI1, LL_SPI_NSS_SOFT); //LL_SPI_NSS_HARD_INPUT
LL_SPI_SetMode(SPI1, LL_SPI_MODE_MASTER);
}
else if(a_nMasterSlave == SPI_SLAVE){
LL_GPIO_SetPinMode(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_MODE_ALTERNATE); //LL_GPIO_MODE_INPUT
LL_GPIO_SetPinSpeed(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetAFPin_8_15(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_AF_5);
LL_GPIO_SetPinPull(SPI1_NSS_PORT, SPI1_NSS_PIN, LL_GPIO_PULL_DOWN);

LL_SPI_SetNSSMode(SPI1, LL_SPI_NSS_HARD_INPUT); //LL_SPI_NSS_SOFT
LL_SPI_SetMode(SPI1, LL_SPI_MODE_SLAVE);
}

if(a_chDMA == eInterruptDisable){
if(a_chInt == eInterruptEnable){
/* (2) Configure NVIC for SPI1 transfer complete/error interrupts **********/
/* Set priority for SPI1_IRQn */
NVIC_SetPriority(SPI1_IRQn, 1);
/* Enable SPI1_IRQn           */
NVIC_EnableIRQ(SPI1_IRQn);

/* Configure SPI1 transfer interrupts */
/* Enable RXNE  Interrupt             */
LL_SPI_EnableIT_RXNE(SPI1);
/* Enable TXE   Interrupt             */
  LL_SPI_EnableIT_TXE(SPI1);
/* Enable Error Interrupt             */
LL_SPI_EnableIT_ERR(SPI1);
}
}
else if(a_chDMA == eInterruptEnable){
/* Configure SPI1 DMA transfer interrupts */
/* Enable DMA RX Interrupt */
LL_SPI_EnableDMAReq_RX(SPI1);
/* Enable DMA TX Interrupt */
LL_SPI_EnableDMAReq_TX(SPI1);


 /* DMA1 used for SPI1 Transmission
 * DMA1 used for SPI1 Reception
 */
/* (1) Enable the clock of DMA1 and DMA1 */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);

 /* (2) Configure NVIC for DMA transfer complete/error interrupts */
NVIC_SetPriority(DMA1_Channel2_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
NVIC_SetPriority(DMA1_Channel3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel3_IRQn);

/* (3) Configure the DMA1_Channel2 functional parameters */
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_2,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL |
LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, LL_SPI_DMA_GetRegAddr(SPI1), (uint32_t)Spi1.RxBuf,
 LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, SPIRBUF_SIZE);//Data Size
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMA_REQUEST_1);

/* (4) Configure the DMA1_Channel3 functional parameters */
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_3,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL |
LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_3, (uint32_t)Spi1.TxBuf, LL_SPI_DMA_GetRegAddr(SPI1),
 LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, SPIRBUF_SIZE);//Data Size
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMA_REQUEST_1);

/* (5) Enable DMA interrupts complete/error */
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_3);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_3);
}

ClearBuf_SPI1();

LL_SPI_Enable(SPI1);

if(a_chDMA == eInterruptEnable){
/* Enable DMA Channels */
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);
}
  }
  else if(a_chSpi == 2)
{
  }
}

/*******************************************************************************
* Function Name : 
* Parameters    : None
* Return        : None
* Description   : 
*******************************************************************************/
uint8_t SPI_FLASH_ReadWite(SPI_TypeDef *SPI_Num, const uint8_t* pTXBuffer, uint8_t* pRXBuffer, uint16_t NumByteToRead)
{
uint16_t w, b;

CLEAR_BIT(SPI_Num->CR2, SPI_RXFIFO_THRESHOLD);
while (NumByteToRead > 1) {
int spiTimeout = 1000;
while (!LL_SPI_IsActiveFlag_TXE(SPI_Num)) {
if ((spiTimeout--) == 0) {
return 0x02;
}
}

if (pTXBuffer) {
w = *((uint16_t *)pTXBuffer);
pTXBuffer += 2;

else {
w = 0xFFFF;
}
*((__IO uint16_t *)&SPI_Num->DR) = w;//LL_SPI_TransmitData16(SPI_Num, w);

spiTimeout = 1000;
while (!LL_SPI_IsActiveFlag_RXNE(SPI_Num)) {
if ((spiTimeout--) == 0) {
return 0x02;
}
}
w = LL_SPI_ReceiveData16(SPI_Num);
if (pRXBuffer) {
*((uint16_t *)pRXBuffer) = w;
pRXBuffer += 2;
}
NumByteToRead -= 2;
}

// set 8-bit transfer
SET_BIT(SPI_Num->CR2, SPI_RXFIFO_THRESHOLD);
if (NumByteToRead) {
int spiTimeout = 1000;
while (!LL_SPI_IsActiveFlag_TXE(SPI_Num)) {
if ((spiTimeout--) == 0) {
return 0x02;
}
}
b = pTXBuffer ? *(pTXBuffer++) : 0xFF;
*((__IO uint8_t *)&SPI_Num->DR) = b;//LL_SPI_TransmitData8(SPI_Num, b);

spiTimeout = 1000;
while (!LL_SPI_IsActiveFlag_RXNE(SPI_Num)) {
if ((spiTimeout--) == 0) {
return 0x02;
}
}

b = (uint8_t)(READ_REG(SPI_Num->DR));// b = LL_SPI_ReceiveData8(SPI_Num);
if (pRXBuffer) {
*(pRXBuffer++) = b;
}
--NumByteToRead;
}

return 0x00;
}

/*******************************************************************************
* Function Name : 
* Parameters    : None
* Return        : None
* Description   : 
*******************************************************************************/
uint8_t SPI_FLASH_SendByte(SPI_TypeDef *SPI_Num, uint8_t byte)
{
uint32_t SPITimeOut = SPI_FLAG_TIMEOUT;
  /* Loop while DR register in not emplty */
  while (!LL_SPI_IsActiveFlag_TXE(SPI_Num)){
if (SPITimeOut-- == 0) return 0x02;
}

  /* Send byte through the SPI1 peripheral */
*((__IO uint8_t *)&SPI_Num->DR) = byte;// LL_SPI_TransmitData8(SPI_Num, byte);

  /* Wait to receive a byte */
SPITimeOut = SPI_FLAG_TIMEOUT;
  while (!LL_SPI_IsActiveFlag_RXNE(SPI_Num)){
if (SPITimeOut-- == 0) return 0x02;
}

  /* Return the byte read from the SPI bus */
return (uint8_t)(READ_REG(SPI_Num->DR));//  return LL_SPI_ReceiveData8(SPI_Num);
}

/*******************************************************************************
* Function Name : 
* Parameters    : None
* Return        : None
* Description   : 
*******************************************************************************/
uint8_t SPI_FLASH_ReadByte(SPI_TypeDef *SPI_Num)
{
  return (SPI_FLASH_SendByte(SPI_Num, DUMMY_BYTE));
}

'초보의 아웅다웅 설계하기 > STM32' 카테고리의 다른 글

ST의 디자인 툴  (0) 2019.06.04
STM32L4 UART/LPUART LL_DRIVER  (0) 2019.05.25
Keil 자동완성 기능 끄기  (0) 2019.03.21
PID 제어  (0) 2019.03.02
LSM6DSL, LIS2MDL, LPS22HB  (0) 2019.03.01