This commit is contained in:
2026-06-12 02:55:04 -07:00
commit 30406f4f49
2040 changed files with 571534 additions and 0 deletions

280
inc/SPI.c Normal file
View File

@@ -0,0 +1,280 @@
/* SPI.c
* Jonathan Valvano
* November 21, 2022
* Derived from uart_rw_multibyte_fifo_poll_LP_MSPM0G3507_nortos_ticlang
SPI MKII LCD
J1.7 SPI1 SCLK PB9_SPI1-SCK
J2.13 SPI1 CS0 PB6_SPI1-CS0
J2.15 SPI1 PICO PB8_SPI1-PICO
J2.17 LCD !RST PB15
J4.31 LCD RS PB16
*/
#include <ti/devices/msp/msp.h>
#include "../RTOS_Labs_common/SPI.h"
#include "../inc/Clock.h"
#include "../inc/Timer.h"
#include "../inc/LaunchPad.h"
/*
// calls Clock_Freq to get bus clock
// initialize SPI for 8 MHz baud clock
// busy-wait synchronization
// SPI0,SPI1 in power domain PD1 SysClk equals bus CPU clock
void SPI_Init(void){uint32_t busfreq = Clock_Freq();
// assumes GPIOA and GPIOB are reset and powered previously
// RSTCLR to SPI1 peripherals
// bits 31-24 unlock key 0xB1
// bit 1 is Clear reset sticky bit
// bit 0 is reset gpio port
SPI1->GPRCM.RSTCTL = 0xB1000003;
// Enable power to SPI1 peripherals
// PWREN
// bits 31-24 unlock key 0x26
// bit 0 is Enable Power
SPI1->GPRCM.PWREN = 0x26000001;
// configure PB9 PB6 PB8 as alternate SPI1 function
IOMUX->SECCFG.PINCM[PB9INDEX] = 0x00000083; // SPI1 SCLK
IOMUX->SECCFG.PINCM[PB6INDEX] = 0x00000083; // SPI1 CS0
IOMUX->SECCFG.PINCM[PB8INDEX] = 0x00000083; // SPI1 PICO
IOMUX->SECCFG.PINCM[PB15INDEX] = 0x00000081; // GPIO output, LCD !RST
IOMUX->SECCFG.PINCM[PB16INDEX] = 0x00000081; // GPIO output, LCD RS
// ** IOMUX->SECCFG.PINCM[PA13INDEX] = 0x00000081; // GPIO output, LCD RS
Clock_Delay(24); // time for gpio to power up
// ** GPIOA->DOE31_0 |= 1<<13; // PA13 is LCD RS
GPIOB->DOE31_0 |= 1<<16; // PA13 is LCD RS
GPIOB->DOE31_0 |= 1<<15; // PB15 is LCD !RST
GPIOB->DOUTSET31_0 = 1<<16; // RS=1
// ** GPIOA->DOUTSET31_0 = 1<<13; // RS=1
GPIOB->DOUTSET31_0 = 1<<15; // !RST = 1
SPI1->CLKSEL = 8; // SYSCLK
// bit 3 SYSCLK
// bit 2 MFCLK
// bit 1 LFCLK
SPI1->CLKDIV = 0; // divide by 1
// bits 2-0 n (0 to 7), divide by n+1
//Set the bit rate clock divider to generate the serial output clock
// outputBitRate = (spiInputClock) / ((1 + SCR) * 2)
// 8,000,000 = (16,000,000)/((0 + 1) * 2)
// 8,000,000 = (32,000,000)/((1 + 1) * 2)
// 6,666,667 = (40,000,000)/((2 + 1) * 2)
// 10,000,000 = (40,000,000)/((1 + 1) * 2)
// 8,000,000 = (80,000,000)/((4 + 1) * 2)
// 8,000,000 = (Clock_Freq)/((m + 1) * 2)
// m = (Clock_Freq/16000000) - 1
if(busfreq <= 16000000){
SPI1->CLKCTL = 0; // frequency= busfreq/2
}else if(busfreq == 40000000){
SPI1->CLKCTL = 1; // frequency= 10MHz
// SPI1->CLKCTL = 2; // frequency= 6.66MHz
}else{
SPI1->CLKCTL = busfreq/16000000 -1; // 8 MHz
}
SPI1->CTL0 = 0x0027;
// bit 14 CSCLR=0 not cleared
// bits 13-12 CSSEL=0 CS0
// bit 9 SPH = 0
// bit 8 SPO = 0
// bits 6-5 FRF = 01 (4 wire)
// bits 4-0 n=7, data size is n+1 (8bit data)
SPI1->CTL1 = 0x0015;
// bits 29-24 RXTIMEOUT=0
// bits 23-16 REPEATX=0 disabled
// bits 15-12 CDMODE=0 manual
// bit 11 CDENABLE=0 CS3
// bit 7-5 =0 no parity
// bit 4=1 MSB first
// bit 3=0 POD (not used, not peripheral)
// bit 2=1 CP controller mode
// bit 1=0 LBM disable loop back
// bit 0=1 enable SPI
SPI_Reset();
}
//---------SPI_OutData------------
// Output 8-bit data to SPI port
// Input: data is an 8-bit data to be transferred
// Output: none
void SPI_OutData(char data){
while((SPI1->STAT&0x02) == 0x00){}; // spin if TxFifo full
GPIOA->DOUTSET31_0 = 1<<13; // RS=PA13=1 for data
SPI1->TXDATA = data;
}
//---------SPI_OutCommand------------
// Output 8-bit command to SPI port
// Input: data is an 8-bit data to be transferred
// Output: none
void SPI_OutCommand(char command){
while((SPI1->STAT&0x10) == 0x10){}; // spin if SPI busy
GPIOA->DOUTCLR31_0 = 1<<13; // RS=PA13=0 for command
SPI1->TXDATA = command;
while((SPI1->STAT&0x10) == 0x10){}; // spin if SPI busy
}
*/
//---------SPI1_Reset------------
// Reset LCD
// Input: none
// Output: none
// at 48 MHz
void SPI1_Reset(void){
// GPIOB->DOUTSET31_0 = 1<<15; // PB15=!RST=1
TFT_RST_HIGH();
Clock_Delay1ms(500); // 500ms (calibrated with logic analyzer)
//GPIOB->DOUTCLR31_0 = 1<<15; // PB15=!RST=0
TFT_RST_LOW();
Clock_Delay1ms(500); // 500ms
//GPIOB->DOUTSET31_0 = 1<<15; // PB15=!RST=1
TFT_RST_HIGH();
Clock_Delay1ms(500); // 500ms
}
//********SPI1_Init*****************
// Initialize SPI1 interface to SDC and TFT
// inputs: none
// outputs: none
// outputBitRate = (spiInputClock) / ((1 + SCR) * 2)
// 99 for 400,000 bps slow mode, used during initialization
// 4 for 8,000,000 bps fast mode, used during disk I/O
// Version for both SDC and TFT
int LCDresetFlag;
void SPI1_Init(void){
TimerG0_IntArm(1000,40,1); // initialize TimerG0 for 1 ms interrupts
CS_Init(); // initialize whichever GPIO pin is CS for the SD card
uint32_t busfreq = Clock_Freq();
// assumes GPIOA and GPIOB are reset and powered previously
// RSTCLR to SPI1 peripherals
// bits 31-24 unlock key 0xB1
// bit 1 is Clear reset sticky bit
// bit 0 is reset gpio port
SPI1->GPRCM.RSTCTL = 0xB1000003;
// Enable power to SPI1 peripherals
// PWREN
// bits 31-24 unlock key 0x26
// bit 0 is Enable Power
SPI1->GPRCM.PWREN = 0x26000001;
// configure PB9 PB6 PB8 as alternate SPI1 function
IOMUX->SECCFG.PINCM[PB9INDEX] = 0x00000083; // SPI1 SCLK
// IOMUX->SECCFG.PINCM[PB6INDEX] = 0x00000083; // SPI1 CS0
IOMUX->SECCFG.PINCM[PB8INDEX] = 0x00000083; // SPI1 PICO
IOMUX->SECCFG.PINCM[TFT_RST_INDEX] = 0x00000081; // GPIO output, LCD !RST
IOMUX->SECCFG.PINCM[TFT_DC_INDEX] = 0x00000081; // GPIO output, LCD D/C RS
// IOMUX->SECCFG.PINCM[PB15INDEX] = 0x00000081; // GPIO output, LCD !RST
// IOMUX->SECCFG.PINCM[PB16INDEX] = 0x00000081; // GPIO output, LCD RS
// ** IOMUX->SECCFG.PINCM[PA13INDEX] = 0x00000081; // GPIO output, LCD RS
IOMUX->SECCFG.PINCM[PB7INDEX] = 0x00040083; // SPI1 POCI
IOMUX->SECCFG.PINCM[TFT_CS_INDEX] = 0x00000081; // PB6 is regular GPIO
// IOMUX->SECCFG.PINCM[PB6INDEX] = 0x00000081; // PB6 is regular GPIO
Clock_Delay(24); // time for gpio to power up
TFT_DC->DOE31_0 |= TFT_DC_PIN; // PB16 is LCD RS
// GPIOB->DOE31_0 |= 1<<16; // PB16 is LCD RS
// ** GPIOA->DOE31_0 |= 1<<13; // PA13 is LCD RS
TFT_RST->DOE31_0 |= TFT_RST_PIN;
//GPIOB->DOE31_0 |= 1<<15; // PB15 is LCD !RST
// GPIOB->DOUTSET31_0 = 1<<16; // RS=1
TFT_DC_HIGH();
// ** GPIOA->DOUTSET31_0 = 1<<13; // RS=1
// GPIOB->DOUTSET31_0 = 1<<15; // !RST = 1
TFT_RST_HIGH();
TFT_CS->DOE31_0 |= TFT_CS_PIN; // PB6 is regular GPIO
//GPIOB->DOE31_0 |= 1<<6; // PB6 is regular GPIO
SPI1->CLKSEL = 8; // SYSCLK
// bit 3 SYSCLK
// bit 2 MFCLK
// bit 1 LFCLK
SPI1->CLKDIV = 0; // divide by 1
// bits 2-0 n (0 to 7), divide by n+1
//Set the bit rate clock divider to generate the serial output clock
// outputBitRate = (spiInputClock) / ((1 + SCR) * 2)
// 8,000,000 = (16,000,000)/((0 + 1) * 2)
// 8,000,000 = (32,000,000)/((1 + 1) * 2)
// 6,666,667 = (40,000,000)/((2 + 1) * 2)
// 10,000,000 = (40,000,000)/((1 + 1) * 2)
// 8,000,000 = (80,000,000)/((4 + 1) * 2)
// 8,000,000 = (Clock_Freq)/((m + 1) * 2)
// m = (Clock_Freq/16000000) - 1
if(busfreq <= 16000000){
SPI1->CLKCTL = 0; // frequency= busfreq/2
}else if(busfreq == 40000000){
SPI1->CLKCTL = 1; // frequency= 10MHz
// SPI1->CLKCTL = 2; // frequency= 6.66MHz
}else{
SPI1->CLKCTL = busfreq/16000000 -1; // 8 MHz
}
SPI1->CTL0 = 0x0007;
// bit 14 CSCLR=0 not cleared
// bits 13-12 CSSEL=0 CS0
// bit 9 SPH = 0
// bit 8 SPO = 0
// bits 6-5 FRF = 00 (3 wire)
// bits 4-0 n=7, data size is n+1 (8bit data)
SPI1->CTL1 = 0x0015;
// bits 29-24 RXTIMEOUT=0
// bits 23-16 REPEATX=0 disabled
// bits 15-12 CDMODE=0 manual
// bit 11 CDENABLE=0 CS3
// bit 7-5 =0 no parity
// bit 4=1 MSB first
// bit 3=0 POD (not used, not peripheral)
// bit 2=1 CP controller mode
// bit 1=0 LBM disable loop back
// bit 0=1 enable SPI
TFT_CS_HIGH(); // disable LCD
if(LCDresetFlag) return;
LCDresetFlag = 1;
SPI1_Reset();
}
// SDC CS initialization
void CS_Init(void){
IOMUX->SECCFG.PINCM[SDC_CS_INDEX] = (uint32_t) 0x00000081;
// IOMUX->SECCFG.PINCM[PB0INDEX] = (uint32_t) 0x00000081;
// ** IOMUX->SECCFG.PINCM[PA12INDEX] = (uint32_t) 0x00000081;
SDC_CS->DOE31_0 |= SDC_CS_PIN;
SDC_CS_HIGH(); // PB0=1
}
/* STAT register
* 4 BUSY 0h = SPI is in idle mode. 1h = SPI is currently transmitting and/or receiving data, or transmit FIFO is not empty.
3 RNF Receive FIFO not full 0h = Receive FIFO is full. 1h = Receive FIFO is not full.
2 RFE Receive FIFO empty. 0h = Receive FIFO is not empty. 1h = Receive FIFO is empty.
1 TNF Transmit FIFO not full 0h = Transmit FIFO is full. 1h = Transmit FIFO is not full.
0 TFE Transmit FIFO empty. 0h = Transmit FIFO is not empty. 1h = Transmit FIFO is empty.*/
//---------TFT_OutData------------
// Output 8-bit data to SPI port
// Input: data is an 8-bit data to be transferred
// Output: none
void TFT_OutData(char data){char response;
// while((SPI1->STAT&0x02) == 0x00){}; // spin if TxFifo full
while((SPI1->STAT&0x10) == 0x10){}; // spin if SPI busy
SDC_CS_HIGH(); // PB0 high
TFT_CS_LOW(); // PB6 low
// GPIOB->DOUTSET31_0 = 1<<16; // RS=PB16=1 for data
TFT_DC_HIGH(); // RS=PB16=1 for data
// ** GPIOA->DOUTSET31_0 = 1<<13; // RS=PA13=1 for data
SPI1->TXDATA = data;
while((SPI1->STAT&0x04) == 0x04){}; // spin SPI RxFifo empty
response = SPI1->RXDATA; // has no meaning, flush
TFT_CS_HIGH(); // PB6 high
}
//---------TFT_OutCommand------------
// Output 8-bit command to SPI port
// Input: data is an 8-bit data to be transferred
// Output: none
void TFT_OutCommand(char command){char response;
while((SPI1->STAT&0x10) == 0x10){}; // spin if SPI busy
SDC_CS_HIGH(); // PB0 high
TFT_CS_LOW(); // PB6 low
//GPIOB->DOUTCLR31_0 = 1<<16; // RS=PB16=0 for command
TFT_DC_LOW(); // RS=PB16=0 for command
// ** GPIOA->DOUTCLR31_0 = 1<<13; // RS=PA13=0 for command
SPI1->TXDATA = command;
while((SPI1->STAT&0x10) == 0x10){}; // spin if SPI busy
response = SPI1->RXDATA; // has no meaning, flush
TFT_CS_HIGH(); // PB6 high
}