/******************************************************************************* @file spi.c @brief Contains all functions support for spi driver @version 0.0 @date 18. Oct. 2017 @author qing.han SDK_LICENSE *******************************************************************************/ #include "rom_sym_def.h" #include "bus_dev.h" #include "spi.h" #include "gpio.h" #include "error.h" #include #include "pwrmgr.h" #include "clock.h" #include "log.h" #include "jump_function.h" #if DMAC_USE #include "dma.h" #endif typedef struct _spi_Context { spi_Cfg_t cfg; hal_spi_t* spi_info; bool is_slave_mode; spi_xmit_t transmit; } spi_Ctx_t; static spi_Ctx_t m_spiCtx[2]; #define SPI_HDL_VALIDATE(hdl) {if((hdl == NULL) || (hdl->spi_index > 1))\ return PPlus_ERR_INVALID_PARAM;\ if((hdl != m_spiCtx[0].spi_info) && (hdl != m_spiCtx[1].spi_info))\ return PPlus_ERR_NOT_REGISTED;} ////////////////// SPI ///////////////////////////////////////// static void hal_spi_write_fifo(AP_SSI_TypeDef* Ssix,uint8_t len,uint8_t* tx_rx_ptr) { uint8_t i=0; SPI_INDEX_e spi_index = (Ssix == AP_SPI0) ? SPI0 : SPI1; HAL_ENTER_CRITICAL_SECTION(); while(iDataReg = *(tx_rx_ptr+i); } else { Ssix->DataReg = *((uint16_t*)tx_rx_ptr+i); } i++; } HAL_EXIT_CRITICAL_SECTION(); } void spi_int_enable(hal_spi_t* spi_ptr, uint32_t mask) { AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->IMR = mask & 0x11; if(Ssix == AP_SPI0) { JUMP_FUNCTION(SPI0_IRQ_HANDLER) = (uint32_t)&hal_SPI0_IRQHandler; } else { JUMP_FUNCTION(SPI1_IRQ_HANDLER) = (uint32_t)&hal_SPI1_IRQHandler; } NVIC_EnableIRQ((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index)); NVIC_SetPriority((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index), IRQ_PRIO_HAL); } static void spi_int_disable(hal_spi_t* spi_ptr) { AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; NVIC_DisableIRQ((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index)); Ssix->IMR = 0x00; } static void spi_int_handle(uint8_t id, spi_Ctx_t* pctx, AP_SSI_TypeDef* Ssix) { volatile uint8_t spi_irs_status; spi_evt_t evt; uint8_t i, cnt; spi_xmit_t* trans_ptr; trans_ptr = &pctx->transmit; spi_irs_status = Ssix->ISR; if(spi_irs_status & TRANSMIT_FIFO_EMPTY) { cnt = 8 - Ssix->TXFLR; for(i = 0; i< cnt; i++) { if(trans_ptr->tx_buf) { Ssix->DataReg = trans_ptr->tx_buf[trans_ptr->tx_offset ++]; } else { trans_ptr->tx_offset++; Ssix->DataReg = 0; } if(trans_ptr->tx_offset == trans_ptr->xmit_len) { Ssix->IMR = 0x10; m_spiCtx[pctx->spi_info->spi_index].transmit.busy = FALSE; break; } } } if(spi_irs_status & RECEIVE_FIFO_FULL) { cnt = Ssix->RXFTLR; for(i = 0; i< cnt; i++) { trans_ptr->rx_buf[trans_ptr->rx_offset++] = Ssix->DataReg; } if(trans_ptr->rx_offset == trans_ptr->xmit_len) { if(pctx->cfg.force_cs == true) hal_gpio_fmux(pctx->cfg.ssn_pin, Bit_ENABLE); trans_ptr->busy = false; trans_ptr->rx_buf = NULL; trans_ptr->rx_offset = 0; evt.id = id; evt.evt = SPI_RX_COMPLETED; hal_pwrmgr_unlock((MODULE_e)(MOD_SPI0 + id)); pctx->cfg.evt_handler(&evt); evt.evt = SPI_TX_COMPLETED; pctx->cfg.evt_handler(&evt); } } } static void spis_int_handle(uint8_t id, spi_Ctx_t* pctx, AP_SSI_TypeDef* Ssix) { volatile uint8_t spi_irs_status; spi_xmit_t* trans_ptr; spi_evt_t evt; uint16_t i, cnt; trans_ptr = &(pctx->transmit); spi_irs_status = Ssix->ISR; if(spi_irs_status & TRANSMIT_FIFO_EMPTY) { cnt = 8 - Ssix->TXFLR; for(i = 0; i< cnt; i++) { if(trans_ptr->tx_offset == trans_ptr->xmit_len) { Ssix->IMR = 0x10; break; } if(trans_ptr->tx_buf) { Ssix->DataReg = trans_ptr->tx_buf[trans_ptr->tx_offset ++]; } else { trans_ptr->tx_offset ++; Ssix->DataReg = 0; } } } if(spi_irs_status & RECEIVE_FIFO_FULL) { volatile uint32_t garbage; cnt = Ssix->RXFLR; if(trans_ptr->rx_buf) { for(i = 0; i< cnt; i++) { if(trans_ptr->xmit_len > trans_ptr->rx_offset) trans_ptr->rx_buf[trans_ptr->rx_offset++] = Ssix->DataReg; else garbage = Ssix->DataReg; } } else { uint8_t rxbuf[16]; if(trans_ptr->busy) trans_ptr->rx_offset += cnt; for(i = 0; i< cnt; i++) { *(rxbuf+i) = Ssix->DataReg; } evt.id = id; evt.evt = SPI_RX_DATA_S; evt.data = rxbuf; evt.len = cnt; pctx->cfg.evt_handler(&evt); } if(trans_ptr->busy && trans_ptr->rx_offset >= trans_ptr->xmit_len) { memset(trans_ptr, 0, sizeof(spi_xmit_t)); evt.id = id; evt.evt = SPI_RX_COMPLETED; evt.data = NULL; evt.len = cnt; pctx->cfg.evt_handler(&evt); evt.evt = SPI_TX_COMPLETED; pctx->cfg.evt_handler(&evt); } } } /************************************************************************************** @fn hal_SPI0_IRQHandler @brief This function process for spi0 interrupt,when use int please consummate its callbackfunction input parameters @param None. output parameters @param None. @return None. **************************************************************************************/ void __attribute__((used)) hal_SPI0_IRQHandler(void) { spi_Ctx_t* pctx = &m_spiCtx[0]; if(pctx->spi_info == NULL) return; if(pctx->is_slave_mode) spis_int_handle(0, pctx, AP_SPI0); else spi_int_handle(0, pctx, AP_SPI0); } /************************************************************************************** @fn hal_SPI1_IRQHandler @brief This function process for spi1 interrupt,when use int please consummate its callbackfunction input parameters @param None. output parameters @param None. @return None. **************************************************************************************/ void __attribute__((used)) hal_SPI1_IRQHandler(void) { spi_Ctx_t* pctx = &m_spiCtx[1]; if(pctx->spi_info == NULL) return; if(pctx->is_slave_mode) spis_int_handle(1, pctx, AP_SPI1); else spi_int_handle(1, pctx, AP_SPI1); } /************************************************************************************** @fn hal_spi_pin_init @brief This function process for spi pin initial(4 lines);You can use two spi,spi0 and spi1,should programe by USE_AP_SPIX input parameters @param GPIO_Pin_e sck_pin: define sclk pin GPIO_Pin_e ssn_pin: define ssn pin GPIO_Pin_e tx_pin: define transmit pin;when use as master,it's mosi pin;corresponding,use as slave,it's miso GPIO_Pin_e rx_pin: define receive pin;when use as master,it's miso pin;corresponding,use as slave,it's mosi output parameters @param None. @return None. **************************************************************************************/ static void hal_spi_pin_init(hal_spi_t* spi_ptr,GPIO_Pin_e sck_pin,GPIO_Pin_e ssn_pin,GPIO_Pin_e tx_pin,GPIO_Pin_e rx_pin) { if(spi_ptr->spi_index == SPI0) { hal_gpio_fmux_set(sck_pin, FMUX_SPI_0_SCK); hal_gpio_fmux_set(ssn_pin, FMUX_SPI_0_SSN); hal_gpio_fmux_set(tx_pin, FMUX_SPI_0_TX); hal_gpio_fmux_set(rx_pin, FMUX_SPI_0_RX); } else if(spi_ptr->spi_index == SPI1) { hal_gpio_fmux_set(sck_pin, FMUX_SPI_1_SCK); hal_gpio_fmux_set(ssn_pin, FMUX_SPI_1_SSN); hal_gpio_fmux_set(tx_pin, FMUX_SPI_1_TX); hal_gpio_fmux_set(rx_pin, FMUX_SPI_1_RX); } } static void hal_spi_pin_deinit(GPIO_Pin_e sck_pin,GPIO_Pin_e ssn_pin,GPIO_Pin_e tx_pin,GPIO_Pin_e rx_pin) { hal_gpio_fmux(sck_pin, Bit_DISABLE); hal_gpio_fmux(ssn_pin, Bit_DISABLE); hal_gpio_fmux(tx_pin, Bit_DISABLE); hal_gpio_fmux(rx_pin, Bit_DISABLE); } /************************************************************************************** @fn hal_spi_master_init @brief This function process for spi master initial input parameters @param uint32_t baud: baudrate select SPI_SCMOD_e scmod: Serial Clock Polarity and Phase select; SPI_MODE0, //SCPOL=0,SCPH=0(default) SPI_MODE1, //SCPOL=0,SCPH=1 SPI_MODE2, //SCPOL=1,SCPH=0 SPI_MODE3, //SCPOL=1,SCPH=1 SPI_TMOD_e tmod: Transfer Mode SPI_TRXD, //Transmit & Receive(default) SPI_TXD, //Transmit Only SPI_RXD, //Receive Only SPI_EEPROM, //EEPROM Read output parameters @param None. @return None. **************************************************************************************/ static void hal_spi_master_init(hal_spi_t* spi_ptr,uint32_t baud,SPI_SCMOD_e scmod,SPI_TMOD_e tmod) { uint8_t shift = 0; AP_SSI_TypeDef* Ssix = NULL; AP_COM_TypeDef* apcom = AP_COM; uint16_t baud_temp; int pclk = clk_get_pclk(); if(spi_ptr->spi_index == SPI1) { shift = 1; } Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->SSIEN = 0; //DISABLE_SPI; apcom->PERI_MASTER_SELECT |= (BIT(shift)|BIT(shift+4)); Ssix->CR0= ((Ssix->CR0) & 0xfffffc3f)|(scmod<<6)|(tmod<<8); baud_temp = (pclk + (baud>>1)) / baud; if(baud_temp<2) { baud_temp = 2; } else if(baud_temp>65534) { baud_temp =65534; } Ssix->BAUDR= baud_temp; // set clock(round) Ssix->TXFTLR=4; // set fifo threshold to triggle interrupt Ssix->RXFTLR=1; Ssix->IMR = 0x00; Ssix->SER=1; //enable slave device Ssix->SSIEN = 1; //ENABLE_SPI; } /************************************************************************************** @fn hal_spi_slave_init @brief This function process for spi slave initial input parameters @param uint32_t baud: baudrate select SPI_SCMOD_e scmod: Serial Clock Polarity and Phase select; SPI_MODE0, //SCPOL=0,SCPH=0(default) SPI_MODE1, //SCPOL=0,SCPH=1 SPI_MODE2, //SCPOL=1,SCPH=0 SPI_MODE3, //SCPOL=1,SCPH=1 SPI_TMOD_e tmod: Transfer Mode SPI_TRXD, //Transmit & Receive(default) SPI_TXD, //Transmit Only SPI_RXD, //Receive Only SPI_EEPROM, //EEPROM Read output parameters @param None. @return None. **************************************************************************************/ /*static*/ void hal_spi_slave_init(hal_spi_t* spi_ptr,uint32_t baud,SPI_SCMOD_e scmod,SPI_TMOD_e tmod) { uint8_t shift = 0; AP_SSI_TypeDef* Ssix = NULL; AP_COM_TypeDef* apcom = AP_COM; uint16_t baud_temp; int pclk = clk_get_pclk(); if(spi_ptr->spi_index == SPI1) { shift = 1; } Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->SSIEN = 0; //DISABLE_SPI; apcom->PERI_MASTER_SELECT &= ~(BIT(shift)); Ssix->CR0= ((Ssix->CR0) & 0xfffffc3f)|(scmod<<6)|(tmod<<8)|0x400; baud_temp = (pclk + (baud>>1)) / baud; if(baud_temp<2) { baud_temp = 2; } else if(baud_temp>65534) { baud_temp =65534; } Ssix->BAUDR= baud_temp; // set clock(round) Ssix->TXFTLR=4; // set fifo threshold to triggle interrupt Ssix->RXFTLR=1; //threshold is 1 Ssix->IMR=0x11; //enable tx and rx // Ssix->SER=1; //enable slave device Ssix->SSIEN = 1; //ENABLE_SPI; } #if DMAC_USE static void config_dma_channel4spitx(hal_spi_t* spi_ptr,uint8_t* tx_buf,uint16_t tx_len) { DMA_CH_CFG_t cfgc; AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->DMACR &= 0x01; spi_Ctx_t* pctx; pctx = &m_spiCtx[spi_ptr->spi_index]; cfgc.sinc = DMA_INC_INC; if(pctx->cfg.spi_dfsmod <= SPI_1BYTE) { hal_spi_dfs_set(spi_ptr,SPI_1BYTE); cfgc.transf_size = tx_len; cfgc.src_tr_width = DMA_WIDTH_BYTE; cfgc.dst_tr_width = DMA_WIDTH_BYTE; cfgc.src_addr = (uint32_t)tx_buf; } else { uint16_t* size16_tx_buf = (uint16_t*)tx_buf; hal_spi_dfs_set(spi_ptr,SPI_2BYTE); cfgc.transf_size = tx_len/2; cfgc.src_tr_width = DMA_WIDTH_HALFWORD; cfgc.dst_tr_width = DMA_WIDTH_HALFWORD; cfgc.src_addr = (uint32_t)size16_tx_buf; } cfgc.src_msize = DMA_BSIZE_1; cfgc.dinc = DMA_INC_NCHG; cfgc.dst_msize = DMA_BSIZE_1; cfgc.dst_addr = (uint32_t)&(Ssix->DataReg); cfgc.enable_int = false; hal_dma_config_channel(DMA_CH_0,&cfgc); hal_dma_start_channel(DMA_CH_0); Ssix->DMACR |= 0x02; Ssix->DMATDLR = 0; } static void config_dma_channel4spirx(hal_spi_t* spi_ptr,uint8_t* rx_buf,uint16_t rx_len) { DMA_CH_CFG_t cfgc; AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->DMACR &= 0x02; cfgc.transf_size = rx_len; cfgc.sinc = DMA_INC_NCHG; cfgc.src_tr_width = DMA_WIDTH_BYTE; cfgc.src_msize = DMA_BSIZE_1; cfgc.src_addr = (uint32_t)&(Ssix->DataReg); cfgc.dinc = DMA_INC_INC; cfgc.dst_tr_width = DMA_WIDTH_BYTE; cfgc.dst_msize = DMA_BSIZE_1; cfgc.dst_addr = (uint32_t)rx_buf; cfgc.enable_int = false; hal_dma_config_channel(DMA_CH_0,&cfgc); hal_dma_start_channel(DMA_CH_0); Ssix->DMACR |= 0x01; Ssix->DMARDLR = 0; } #endif static int hal_spi_xmit_polling ( hal_spi_t* spi_ptr, uint8_t* tx_buf, uint8_t* rx_buf, uint16_t tx_len, uint16_t rx_len ) { uint32_t rx_size = rx_len, tx_size = tx_len; uint32_t tmp_len,i,tmp_tx_buf_len = 0; AP_SSI_TypeDef* Ssix = NULL; #if DMAC_USE spi_Ctx_t* pctx; pctx = &m_spiCtx[spi_ptr->spi_index]; #endif Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; SPI_INIT_TOUT(to); #if DMAC_USE if(rx_len && pctx->cfg.dma_rx_enable) { config_dma_channel4spirx(spi_ptr,rx_buf,rx_len); } else if(tx_len && pctx->cfg.dma_tx_enable) { config_dma_channel4spitx(spi_ptr,tx_buf,tx_len); } #endif while(1) { if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size #if DMAC_USE && !(pctx->cfg.dma_tx_enable) #endif ) //#if DMAC_USE // if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size && !(pctx->cfg.dma_tx_enable)) //#else // if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size) //#endif { tmp_len = 8-Ssix->TXFLR; if(tmp_len > tx_size) tmp_len = tx_size; if(tx_buf) { //support divider 2 if (m_spiCtx[spi_ptr->spi_index].cfg.spi_dfsmod <= SPI_1BYTE) { switch (tmp_len) { case 1: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); tmp_tx_buf_len += 1; break; case 2: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); tmp_tx_buf_len += 2; break; case 3: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); tmp_tx_buf_len += 3; break; case 4: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+3); tmp_tx_buf_len += 4; break; case 5: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+4); tmp_tx_buf_len += 5; break; case 6: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+5); tmp_tx_buf_len += 6; break; case 7: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+5); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+6); tmp_tx_buf_len += 7; break; case 8: Ssix->DataReg = *(tx_buf+tmp_tx_buf_len); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+5); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+6); Ssix->DataReg = *(tx_buf+tmp_tx_buf_len+7); tmp_tx_buf_len += 8; break; default: break; } } else { switch (tmp_len) { case 1: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); tmp_tx_buf_len += 1; break; case 2: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); tmp_tx_buf_len += 2; break; case 3: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); tmp_tx_buf_len += 3; break; case 4: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+3); tmp_tx_buf_len += 4; break; case 5: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+4); tmp_tx_buf_len += 5; break; case 6: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+5); tmp_tx_buf_len += 6; break; case 7: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+5); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+6); tmp_tx_buf_len += 7; break; case 8: Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+1); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+2); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+3); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+4); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+5); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+6); Ssix->DataReg = *((uint16_t*)tx_buf+tmp_tx_buf_len+7); tmp_tx_buf_len += 8; break; default: break; } } } else { for(i = 0; i< tmp_len; i++) { Ssix->DataReg = 0; } } tx_size -= tmp_len; } #if DMAC_USE if(((rx_len == 0) && ((tx_size == 0)||(tx_size && (pctx->cfg.dma_tx_enable)))) || (rx_len && (tx_size == 0) && (pctx->cfg.dma_rx_enable))) break; else if(rx_len && !(pctx->cfg.dma_rx_enable)) #else if((rx_len == 0) && ((tx_size == 0))) break; else if(rx_len) #endif { if(Ssix->RXFLR) { tmp_len = Ssix->RXFLR; for(i = 0; i< tmp_len; i++) { *rx_buf++= Ssix->DataReg; } rx_size -= tmp_len; } if(rx_size == 0) break; } SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_xmit_polling TO\n"); } #if DMAC_USE if((pctx->cfg.dma_rx_enable) || (pctx->cfg.dma_tx_enable)) hal_dma_status_control(DMA_CH_0); #endif while(Ssix->SR & SPI_BUSY) { SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_xmit_polling TO\n"); } return PPlus_SUCCESS; } static void spi0_sleep_handler(void) { if(m_spiCtx[0].spi_info != NULL) hal_spi_bus_deinit(m_spiCtx[0].spi_info); } static void spi1_sleep_handler(void) { if(m_spiCtx[1].spi_info != NULL) hal_spi_bus_deinit(m_spiCtx[1].spi_info); } static void spi0_wakeup_handler(void) { NVIC_SetPriority((IRQn_Type)SPI0_IRQn, IRQ_PRIO_HAL); } static void spi1_wakeup_handler(void) { NVIC_SetPriority((IRQn_Type)SPI1_IRQn, IRQ_PRIO_HAL); } void hal_spi_tmod_set(hal_spi_t* spi_ptr,SPI_TMOD_e mod) { AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->SSIEN = 0; subWriteReg(&Ssix->CR0,9,8,mod); Ssix->SSIEN = 1; } void hal_spi_dfs_set(hal_spi_t* spi_ptr,SPI_DFS_e mod) { AP_SSI_TypeDef* Ssix = NULL; spi_Ctx_t* pctx; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; pctx = &m_spiCtx[spi_ptr->spi_index]; Ssix->SSIEN = 0; subWriteReg(&Ssix->CR0,3,0,mod); Ssix->SSIEN = 1; pctx->cfg.spi_dfsmod = mod; } static void hal_spi_ndf_set(hal_spi_t* spi_ptr,uint16_t len) { AP_SSI_TypeDef* Ssix = NULL; if(len == 0) return; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; Ssix->SSIEN = 0; Ssix->CR1 = len-1; Ssix->SSIEN = 1; } int hal_spi_transmit ( hal_spi_t* spi_ptr, SPI_TMOD_e mod, uint8_t* tx_buf, uint8_t* rx_buf, uint16_t tx_len, uint16_t rx_len ) { int ret; spi_Ctx_t* pctx; AP_SSI_TypeDef* Ssix = NULL; spi_xmit_t* trans_ptr; SPI_HDL_VALIDATE(spi_ptr); pctx = &m_spiCtx[spi_ptr->spi_index]; trans_ptr = &(pctx->transmit); if(((tx_len == 0)&&(rx_len == 0))||(mod > SPI_EEPROM)||(tx_buf == NULL)) return PPlus_ERR_INVALID_PARAM; if(pctx->transmit.busy == true) return PPlus_ERR_BUSY; #if DMAC_USE if((pctx->cfg.dma_rx_enable && (rx_len==0)) || (pctx->cfg.dma_tx_enable && (tx_len==0))) { return PPlus_ERR_INVALID_PARAM; } #endif Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; hal_spi_tmod_set(spi_ptr,mod); if(mod > SPI_TXD) //spi receive only or eeprom read,should set read data len(ndf) { hal_spi_ndf_set(spi_ptr,rx_len); } if(pctx->cfg.force_cs == true /*&& pctx->is_slave_mode == FALSE*/) { hal_gpio_fmux(pctx->cfg.ssn_pin,Bit_DISABLE); hal_gpio_write(pctx->cfg.ssn_pin,0); } if(pctx->cfg.int_mode == false) { ret = hal_spi_xmit_polling(spi_ptr,tx_buf, rx_buf, tx_len,rx_len); if(pctx->cfg.force_cs == true && pctx->is_slave_mode == FALSE) hal_gpio_fmux(pctx->cfg.ssn_pin,Bit_ENABLE); if(ret) return PPlus_ERR_TIMEOUT; } else { spi_int_disable(spi_ptr); if(trans_ptr->buf_len < tx_len) return PPlus_ERR_NO_MEM; if(tx_buf) { if(!trans_ptr->tx_buf) return PPlus_ERR_NO_MEM; } trans_ptr->tx_offset = 0; memcpy(trans_ptr->tx_buf,tx_buf,tx_len); if(Ssix->SR & TX_FIFO_NOT_FULL) { uint16_t _tx_len; uint8_t dummy[8]; if(rx_buf) { trans_ptr->rx_buf = rx_buf; } hal_pwrmgr_lock((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); _tx_len = (tx_len >= 8)?8:tx_len; if(trans_ptr->tx_buf) { trans_ptr->tx_offset += _tx_len; hal_spi_write_fifo(Ssix,_tx_len,tx_buf); } else { hal_spi_write_fifo(Ssix,_tx_len,dummy); } trans_ptr->xmit_len = tx_len; } pctx->transmit.busy = true; spi_int_enable(spi_ptr, 0x11); } return PPlus_SUCCESS; } int hal_spi_set_tx_buffer(hal_spi_t* spi_ptr,uint8_t* tx_buf,uint16_t len) { SPI_HDL_VALIDATE(spi_ptr); if((tx_buf == NULL) || (len == 0)) return PPlus_ERR_INVALID_PARAM; m_spiCtx[spi_ptr->spi_index].transmit.tx_buf = tx_buf;//used when tx int m_spiCtx[spi_ptr->spi_index].transmit.buf_len = len; return PPlus_SUCCESS; } int hal_spi_set_int_mode(hal_spi_t* spi_ptr,bool en) { SPI_HDL_VALIDATE(spi_ptr); m_spiCtx[spi_ptr->spi_index].cfg.int_mode = en; if(en) { m_spiCtx[spi_ptr->spi_index].cfg.int_mode = true; spi_int_enable(spi_ptr, 0x10); } else { m_spiCtx[spi_ptr->spi_index].cfg.int_mode = false; spi_int_disable(spi_ptr); } return PPlus_SUCCESS; } int hal_spi_set_force_cs(hal_spi_t* spi_ptr,bool en) { SPI_HDL_VALIDATE(spi_ptr); m_spiCtx[spi_ptr->spi_index].cfg.force_cs = en; return PPlus_SUCCESS; } bool hal_spi_get_transmit_bus_state(hal_spi_t* spi_ptr) { return m_spiCtx[spi_ptr->spi_index].transmit.busy; } int hal_spi_TxComplete(hal_spi_t* spi_ptr) { AP_SSI_TypeDef* Ssix = NULL; SPI_HDL_VALIDATE(spi_ptr); Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; SPI_INIT_TOUT(to); while(Ssix->SR & SPI_BUSY) { SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_TxComplete TO\n"); } return PPlus_SUCCESS; } int hal_spi_send_byte(hal_spi_t* spi_ptr,uint8_t data) { AP_SSI_TypeDef* Ssix = NULL; SPI_HDL_VALIDATE(spi_ptr); Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; if(Ssix->SR & TX_FIFO_NOT_FULL) { Ssix->DataReg = data & 0xff; SPI_INIT_TOUT(to); while(Ssix->SR & SPI_BUSY) { SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT,"hal_spi_send_byte TO\n"); } } return PPlus_SUCCESS; } int hal_spi_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg) { spi_Ctx_t* pctx = NULL; if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) return PPlus_ERR_INVALID_PARAM; pctx = &m_spiCtx[spi_ptr->spi_index]; if(pctx->spi_info != NULL) return PPlus_ERR_BUSY; hal_clk_gate_enable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); hal_spi_pin_init(spi_ptr,cfg.sclk_pin,cfg.ssn_pin,cfg.MOSI,cfg.MISO); hal_spi_master_init(spi_ptr,cfg.baudrate, cfg.spi_scmod, cfg.spi_tmod); hal_spi_dfs_set(spi_ptr,cfg.spi_dfsmod); pctx->cfg = cfg; pctx->transmit.busy = false; pctx->spi_info = spi_ptr; if(cfg.int_mode) spi_int_enable(spi_ptr, 0x10); else spi_int_disable(spi_ptr); pctx->is_slave_mode = false; return PPlus_SUCCESS; } int hal_spis_clear_rx(hal_spi_t* spi_ptr) { AP_SSI_TypeDef* Ssix = NULL; volatile uint8_t rx; SPI_HDL_VALIDATE(spi_ptr); Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; while(Ssix->RXFLR) { rx = Ssix->DataReg; } return (int)rx; } uint32_t hal_spis_rx_len(hal_spi_t* spi_ptr) { AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; return Ssix->RXFLR; } int hal_spis_read_rxn(hal_spi_t* spi_ptr, uint8_t* pbuf, uint16_t len) { AP_SSI_TypeDef* Ssix = NULL; Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; while(len) { *pbuf = Ssix->DataReg; pbuf ++; len --; } return PPlus_SUCCESS; } int hal_spis_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg) { spi_Ctx_t* pctx = NULL; if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) return PPlus_ERR_INVALID_PARAM; pctx = &m_spiCtx[spi_ptr->spi_index]; if(pctx->spi_info != NULL) return PPlus_ERR_BUSY; hal_clk_gate_enable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); hal_spi_pin_init(spi_ptr,cfg.sclk_pin,cfg.ssn_pin,cfg.MOSI,cfg.MISO); hal_spi_slave_init(spi_ptr,cfg.baudrate, cfg.spi_scmod, cfg.spi_tmod); pctx->cfg = cfg; memset(&(pctx->transmit), 0, sizeof(spi_xmit_t)); pctx->spi_info = spi_ptr; pctx->is_slave_mode = true; if(cfg.int_mode) spi_int_enable(spi_ptr, 0x10); else spi_int_disable(spi_ptr); return PPlus_SUCCESS; } /************************************************************************************** @fn hal_spi_deinit @brief This function will deinit the spi you select. input parameters @param hal_spi_t* spi_ptr: spi module handle. output parameters @param None. @return PPlus_SUCCESS PPlus_ERR_INVALID_PARAM **************************************************************************************/ int hal_spi_bus_deinit(hal_spi_t* spi_ptr) { SPI_HDL_VALIDATE(spi_ptr); hal_clk_gate_disable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); //spi_int_disable(spi_ptr); hal_spi_pin_deinit(m_spiCtx[spi_ptr->spi_index].cfg.sclk_pin,m_spiCtx[spi_ptr->spi_index].cfg.ssn_pin,m_spiCtx[spi_ptr->spi_index].cfg.MOSI,m_spiCtx[spi_ptr->spi_index].cfg.MISO); memset(&m_spiCtx,0,2*sizeof(spi_Ctx_t)); return PPlus_SUCCESS; } /************************************************************************************** @fn hal_spi_init @brief it is used to init spi module. input parameters @param None output parameters @param None. @return None. **************************************************************************************/ int hal_spi_init(SPI_INDEX_e channel) { int ret = 0; if(channel == SPI0) { ret = hal_pwrmgr_register(MOD_SPI0,spi0_sleep_handler, spi0_wakeup_handler); if(ret == PPlus_SUCCESS) memset(&m_spiCtx[0],0,sizeof(spi_Ctx_t)); return ret; } else if(channel == SPI1) { ret = hal_pwrmgr_register(MOD_SPI1,spi1_sleep_handler, spi1_wakeup_handler); if(ret == PPlus_SUCCESS) memset(&m_spiCtx[1],0,sizeof(spi_Ctx_t)); return ret; } return PPlus_ERR_INVALID_PARAM; } #if DMAC_USE int hal_spi_dma_set(hal_spi_t* spi_ptr,bool ten,bool ren) { spi_Ctx_t* pctx = NULL; if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) return PPlus_ERR_INVALID_PARAM; pctx = &m_spiCtx[spi_ptr->spi_index]; pctx->cfg.dma_rx_enable = ren; pctx->cfg.dma_tx_enable = ten; return PPlus_SUCCESS; } #endif