Files
TweinStein/RTOS_Lab3_RTOSpriority/SPI1.c
2026-06-12 02:55:04 -07:00

304 lines
11 KiB
C

/* SPI1.c
* Jonathan Valvano
* December 27, 2025
* Derived from uart_rw_multibyte_fifo_poll_LP_MSPM0G3507_nortos_ticlang
*/
// hardware connections, ECE445M RTOS sensor board
// **********Adafruit ST7735 TFT and SDC*******************
// ST7735
// Backlight (pin 10) to +3.3 V
// MISO (pin 9) to SPI1 POCI: PB7
// SCK (pin 8) to SPI1 SCLK: PB9
// MOSI (pin 7) to SPI1 PICO: PB8
// TFT_CS (pin 6) to GPIO: PB6
// CARD_CS (pin 5) to PB0 (GPIO)
// Data/Command (pin 4) to PB16 (GPIO), high for data, low for command
// RESET (pin 3) to PB15 (GPIO)
// VCC (pin 2) to +3.3 V
// Gnd (pin 1) to ground
// **********HiLetgo ST7735 TFT and SDC (SDC not tested)*******************
// ST7735
// LED- (pin 16) TFT, to ground
// LED+ (pin 15) TFT, to +3.3 V
// SD_CS (pin 14) SDC, to PB0 chip select
// MOSI (pin 13) SDC, to PB8 MOSI
// MISO (pin 12) SDC, to PB7 MISO
// SCK (pin 11) SDC, to serial clock
// CS (pin 10) TFT, to PB6 GPIO
// SCL (pin 9) TFT, to PB9 SPI1 SCLK
// SDA (pin 8) TFT, to PB8 MOSI SPI1 PICO
// A0 (pin 7) TFT, to PB16 Data/Command, high for data, low for command
// RESET (pin 6) TFT, to PB15 reset (GPIO), low to reset
// NC (pins 3,4,5)
// VCC (pin 2) to +3.3 V
// GND (pin 1) to ground
#include <ti/devices/msp/msp.h>
#include "../RTOS_Labs_common/SPI1.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
}