#include "board.h" #define TDC_SPI_CR2_BSC ((0<<6) | /* RXNEIE, RX not empty interrupt 0:off; 1:on; */ \ (0<<5) | /* TXEIE, TX empty interrupt 0:off; 1:on; */ \ (0<<4) | /* HDMATX, hard DMA TX 0:off; 1:on; */ \ (0<<3) | /* HDMARX, hard DMA RX 0:off; 1:on; */ \ (0<<2) | /* INT_EN, SPI interrupt 0:off; 1:on; */ \ (3<<0)) /* 2 RSV bits */ #define TDC_DMA_CONFA_BSC ((0u<<29) | /* ST, 0:no soft start DMA; 1:soft start DMA */ \ (0x42u<<22) | /* TRI_SEL, 0x40:SPI0 RX; 0x42:SPI1 RX */ \ (0u<<16)) /* BC, one trigger require 0:one; 1:two; ... 15:sixteen data(8/16/32 bits per data) */ uint8_t tdc_spi_rbuf[5]; // 4-wire SPI (2.5V) // fclk <= 15M // Pulse width >= 30 ns // CPOL = 0 (SCK is low when idle) // CPHA = 1 (capture data at falling edge of SCK) // assert SSN at least 40ns before SCLK rising // deassert SSN at least 40ns after SCLK falling // MSB first void tdc_spi_init(void) { // SPI GPIO Configuration // PC02 : SPI1_MISO GpioInit(PC02_SPI1_MISO, GPIO_DIG_IN_NONEUP_PULLDOWN); PeriClk_MutEnable(PeriClk_Spi1); M0P_SPI1->CR = (0<<7) | // SPR2 (0<<6) | // SPEN, 0:off; 1:on; (1<<4) | // MSTR, 0:slave; 1:master; (0<<3) | // CPOL, when idle 0:SCK is low; 1:SCK is high; (1<<2) | // CPHA, 0:1st; 1:2nd; SCK edge sample data (0<<0); // [SPR1:SPR0], 0:PCLK/2; 1:PCLK/4; M0P_SPI1->CR2 = TDC_SPI_CR2_BSC; M0P_SPI1->SSN = 1; M0P_SPI1->CR_f.SPEN = 1; PeriClk_MutDisable(PeriClk_Spi1); // SPI GPIO Configuration // PD00 : SPI1_CS // PD01 : SPI1_SCK // PC03 : SPI1_MOSI GpioInit(PD00_SPI1_CS, GPIO_DIG_OUT_STRN_PUSH_NONEUP_NONEDOWN); GpioInit(PD01_SPI1_SCK, GPIO_DIG_OUT_STRN_PUSH_NONEUP_NONEDOWN); GpioInit(PC03_SPI1_MOSI, GPIO_DIG_OUT_STRN_PUSH_NONEUP_NONEDOWN); DMA_ReqClkOn(); M0P_DMAC->CONF = (1u<<31) | // EN, 0:DMAC off; 1:DMAC on; (0u<<28) | // PRIO, 0:priority of CH0 higher than CH1; 1:round-robin between CH0 and CH1; (0u<<24); // HALT, 0:not halt; others:halt all CH; M0P_DMAC->CONFB0 = (0u<<28) | // MODE, 0:Block; 1:Burst(non interruptible between TC+1 Trigger); (0u<<26) | // WIDTH, 0:8 bits; 1:16 bits; 2:32 bits; (1u<<25) | // FS, source address 0:inc; 1:fixed; (0u<<24) | // FD, destination address 0:inc; 1:fixed; (0u<<20) | // ERR_IE, interrupt 0:off; 1:on; when DMA error (0u<<19) | // FIS_IE, interrupt 0:off; 1:on; after DMA done (0u<<0); // MSK, 0:clear ENS 1:keep ENS; after DMA done M0P_DMAC->SRCADR0 = (uint32_t)&(M0P_SPI1->DATA); M0P_DMAC->DSTADR0 = (uint32_t)&(tdc_spi_rbuf[0]); DMA_ReqClkOff(); } void spi1_wr_byte(uint8_t byte) { while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } M0P_SPI1->DATA = byte; } uint8_t spi1_rd_byte(void) { M0P_SPI1->DATA = 0x00u; // write any data while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } while(M0P_SPI1->STAT_f.BUSY){ // more reliable than RXNE // loop wait until not busy } return(M0P_SPI1->DATA); } void spi1_wait_busy(void) { while(M0P_SPI1->STAT_f.BUSY){ // more reliable than RXNE // loop wait until not busy } } void tdc_spi_wr_d32(uint8_t code, uint32_t data) { uint8_t i; // assert CSN M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high M0P_SPI1->DATA = code; for(i=0;i<4;i++){ while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } M0P_SPI1->DATA = data>>24; // MSB first data = data<<8; } while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } while(M0P_SPI1->STAT_f.BUSY){ // loop wait until not busy } // deassert CSN and clear RXN(hardwareE) M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high // M0P_SPI1->ICLR = 0x0; // clr RX flag(rising of SSN clear rx flag automatically) } void tdc_spi_wr_code(uint8_t code) { // assert CSN M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high M0P_SPI1->DATA = code; while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } while(M0P_SPI1->STAT_f.BUSY){ // loop wait until not busy } // deassert CSN and clear RXNE(hardware) M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high // M0P_SPI1->ICLR = 0x0; // clr RX flag(rising of SSN clear rx flag automatically) } uint32_t tdc_spi_rd_d32(uint8_t code) { uint8_t i; uint32_t data; // assert CSN M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high // enable DMAR of SPI M0P_SPI1->CR2 = TDC_SPI_CR2_BSC | (1<<3); // HDMARX, hard DMA RX 0:off; 1:on; // reload DSTADR because INC M0P_DMAC->DSTADR0 = (uint32_t)&(tdc_spi_rbuf[0]); // enable DMA channel M0P_DMAC->CONFA0 = TDC_DMA_CONFA_BSC | (1u<<31) | /* ENS, 0:CHx off; 1:CHx on; */ ((5-1)<<0); /* TC = Len - 1, close DAM after (TC+1)*(BC+1) */ M0P_SPI1->DATA = code; for(i=0;i<4;i++){ while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } M0P_SPI1->DATA = 0x00; // __asm volatile("nop"); // adding "NOP" maybe decrease checking TXFE rounds // __asm volatile("nop"); // __asm volatile("nop"); } while(M0P_DMAC->CONFA0 & (0x1u<<31)){ // wait until DMA ch0 full done } // disable DMAR of SPI M0P_SPI1->CR2 = TDC_SPI_CR2_BSC; data = tdc_spi_rbuf[1]; data = data<<8; data |= tdc_spi_rbuf[2]; data = data<<8; data |= tdc_spi_rbuf[3]; data = data<<8; data |= tdc_spi_rbuf[4]; // deassert CSN M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high return(data); } uint16_t tdc_spi_rd_d16(uint8_t code) { uint8_t i; uint16_t data; // assert CSN M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high // enable DMAR of SPI M0P_SPI1->CR2 = TDC_SPI_CR2_BSC | (1<<3); // HDMARX, hard DMA RX 0:off; 1:on; // reload DSTADR because INC M0P_DMAC->DSTADR0 = (uint32_t)&(tdc_spi_rbuf[0]); // enable DMA channel M0P_DMAC->CONFA0 = TDC_DMA_CONFA_BSC | (1u<<31) | /* ENS, 0:CHx off; 1:CHx on; */ ((3-1)<<0); /* TC = Len - 1, close DAM after (TC+1)*(BC+1) */ M0P_SPI1->DATA = code; // more faster, if send one byte before start DMA enable for(i=0;i<2;i++){ while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } M0P_SPI1->DATA = 0x00; // __asm volatile("nop"); // adding "NOP" maybe decrease checking TXFE rounds // __asm volatile("nop"); // __asm volatile("nop"); } while(M0P_DMAC->CONFA0 & (0x1u<<31)){ // wait until DMA ch0 full done } // disable DMAR of SPI M0P_SPI1->CR2 = TDC_SPI_CR2_BSC; data = tdc_spi_rbuf[1]; data = data<<8; data |= tdc_spi_rbuf[2]; // deassert CSN M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high return(data); } //uint16_t tdc_spi_rd_d16(uint8_t code) //{ // uint16_t data; // // // assert CSN // M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high // // M0P_SPI1->DATA = code; // more faster, if send one byte before start DMA enable // // while(M0P_SPI1->STAT_f.TXE==0x0u){ // // loop wait until tx buffer is empty // } // M0P_SPI1->DATA = 0x00; // // while(M0P_SPI1->STAT_f.TXE==0x0u){ // // loop wait until tx buffer is empty // } // while(M0P_SPI1->STAT_f.BUSY){ // // loop wait until not busy // } // data = M0P_SPI1->DATA; // // M0P_SPI1->DATA = 0x00; // // while(M0P_SPI1->STAT_f.TXE==0x0u){ // // loop wait until tx buffer is empty // } // while(M0P_SPI1->STAT_f.BUSY){ // // loop wait until not busy // } // data <<= 8; // data |= M0P_SPI1->DATA & 0xFF; // // // deassert CSN // M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high // // return(data); //} uint8_t tdc_spi_rd_d8(uint8_t code) { uint8_t data; // assert CSN M0P_SPI1->SSN = 0; // 0:SPI_CS low; 1:SPI_CS high M0P_SPI1->DATA = code; // more faster, if send one byte before start DMA enable while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } M0P_SPI1->DATA = 0x00; while(M0P_SPI1->STAT_f.TXE==0x0u){ // loop wait until tx buffer is empty } while(M0P_SPI1->STAT_f.BUSY){ // loop wait until not busy } data = M0P_SPI1->DATA; // deassert CSN M0P_SPI1->SSN = 1; // 0:SPI_CS low; 1:SPI_CS high return(data); }