From 79b6705bfc60ed17ddbf6c36ead99e9f5c3c7404 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 26 Feb 2014 21:06:30 +0100 Subject: Old SPI code is now disabled, new SPI code succesfully reads out WM8523 chip id. Needs lots of cleaning... --- firmware/Makefile | 7 +- firmware/drivers/GPIO.c | 171 ++++++++++++++ firmware/drivers/GPIO.h | 21 ++ firmware/drivers/spi.c | 35 +-- firmware/drivers/ssp.c | 413 +++++++++++++++++++++++++++++++++ firmware/drivers/ssp.h | 121 ++++++++++ firmware/drivers/timer.c | 572 ++++++++++++++++++++++++++++++++++++++++++++++ firmware/drivers/timer.h | 47 ++++ firmware/drivers/wm8523.c | 12 +- firmware/src/p2m.c | 152 ++++++++++-- 10 files changed, 1515 insertions(+), 36 deletions(-) create mode 100644 firmware/drivers/GPIO.c create mode 100644 firmware/drivers/GPIO.h create mode 100644 firmware/drivers/ssp.c create mode 100644 firmware/drivers/ssp.h create mode 100644 firmware/drivers/timer.c create mode 100644 firmware/drivers/timer.h diff --git a/firmware/Makefile b/firmware/Makefile index f7edae3..acd193f 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -25,7 +25,7 @@ RM = rm #Q = # @./quiet "$@" # Flags -CFLAGS = -W -Wall -O0 --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb +CFLAGS = -W -Wall -Werror -O0 --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb CFLAGS += -ffunction-sections -fdata-sections CFLAGS += -I${LPC} -I${DRV} ASFLAGS = @@ -45,7 +45,10 @@ LINKER_SCRIPT = ${LPC}/LPC17xx.ld CSRCS = \ ${LPC}/startup_LPC17xx.c \ ${LPC}/system_LPC17xx.c \ - $(wildcard ${SRC}/*.c) + ${LPC}/lpc17xx_spi.c \ + ${LPC}/lpc17xx_clkpwr.c \ + $(wildcard ${SRC}/*.c) \ + $(wildcard ${DRV}/*.c) # ${DRV}/*.c \ diff --git a/firmware/drivers/GPIO.c b/firmware/drivers/GPIO.c new file mode 100644 index 0000000..f89b038 --- /dev/null +++ b/firmware/drivers/GPIO.c @@ -0,0 +1,171 @@ +#include + +//#include "lpc_types.h" +#define FALSE 0 +#define TRUE 1 + +#include "GPIO.h" + +static LPC_GPIO_TypeDef (* const LPC_GPIO[5]) = { LPC_GPIO0, LPC_GPIO1, LPC_GPIO2, LPC_GPIO3, LPC_GPIO4 }; + + +void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal ) +{ + if (bitVal == 0) + { + LPC_GPIO[portNum]->FIOCLR = (1<= 1) + { + LPC_GPIO[portNum]->FIOSET = (1<FIODIR |= 1<FIODIR &= ~(1<PINMODE0 |= dir< 15){ + bitPosi = bitPosi - 16; + bitPosi = bitPosi * 2; + LPC_PINCON->PINMODE1 |= dir<PINMODE2 |= dir< 15){ + bitPosi = bitPosi - 16; + bitPosi = bitPosi * 2; + LPC_PINCON->PINMODE3 |= dir<PINMODE4 |= dir<PINMODE7 |= dir<<18; + }else if (bitPosi == 26){ + LPC_PINCON->PINMODE7 |= dir<<20; + } + + break; + + case 4: + if (bitPosi == 28){ + LPC_PINCON->PINMODE9 |= dir<<24; + }else if (bitPosi == 29){ + LPC_PINCON->PINMODE9 |= dir<<26; + } + + } +} + +uint32_t GPIOGetValue (uint32_t portNum, uint32_t bitPosi) +{ + uint32_t val; + LPC_GPIO[portNum]->FIOMASK = ~(1<FIOPIN; + val = val >> bitPosi; + LPC_GPIO[portNum]->FIOMASK = 0x00000000; + return val; +} + +void GPIOSetInterrupt ( uint32_t portNum, uint32_t bitPosi, uint32_t dir ) +{ + // Dir is 0 for falling edge interrupt and 1 for rising edge interrupt + if (portNum == 0) + { + if (dir == 0) + { + LPC_GPIOINT->IO0IntEnF |= (1<IO0IntEnR |= (1<IO2IntEnF |= (1<IO2IntEnR |= (1<IO0IntClr = 0x7FFF8FFF; + LPC_GPIOINT->IO2IntClr = 0x3fff; +} + +uint32_t GPIOCheckInterrupts ( uint32_t portNum, uint32_t dir) +{ + // Dir is 0 for falling edge interrupt and 1 for rising edge interrupt + if (portNum == 0) + { + if (dir == 0) + { + return LPC_GPIOINT->IO0IntStatF; + } + else if (dir == 1) + { + return LPC_GPIOINT->IO0IntStatR; + } + } + else if (portNum == 2) + { + if (dir == 0) + { + return LPC_GPIOINT->IO0IntStatF; + } + else if (dir == 1) + { + return LPC_GPIOINT->IO0IntStatR; + } + } + return FALSE; +} diff --git a/firmware/drivers/GPIO.h b/firmware/drivers/GPIO.h new file mode 100644 index 0000000..9393edc --- /dev/null +++ b/firmware/drivers/GPIO.h @@ -0,0 +1,21 @@ + +extern void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir ); +extern void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal ); +extern void GPIOSetPull(uint32_t portNum, uint32_t bitPosi, uint32_t dir); +extern uint32_t GPIOGetValue (uint32_t portNum, uint32_t bitPosi); +void GPIOSetInterrupt ( uint32_t portNum, uint32_t bitPosi, uint32_t dir ); +void GPIOClearInterrupt( void ); +uint32_t GPIOCheckInterrupts ( uint32_t portNum, uint32_t dir); + +#define NOPULL 0 +#define PULLUP 1 +#define PULLDOWN 2 + +#define INPUT 0 +#define OUTPUT 1 + +#define FALLING 0 +#define RISING 1 + +#define LOW 0 +#define HIGH 1 diff --git a/firmware/drivers/spi.c b/firmware/drivers/spi.c index 6209a03..fcbb6cc 100644 --- a/firmware/drivers/spi.c +++ b/firmware/drivers/spi.c @@ -28,6 +28,7 @@ #include +#if 0 #define USE_CMSIS @@ -100,7 +101,7 @@ void spi_init() spi_cfg.DataOrder = SPI_DATA_MSB_FIRST; // Se WM8523 manual page 14. Min clock pulse width 40ns ~= 25MHz - spi_cfg.ClockRate = 1000;//1000000000; // 1MHz + spi_cfg.ClockRate = 10000;//1000000000; // 1MHz spi = LPC_SPI; SPI_Init(spi, &spi_cfg); @@ -118,10 +119,10 @@ void spi_init() LPC_SC->PCLKSEL0 |= ((clk & 0x3) << PCLK_SPI_BIT); // set bit 16 and 17 in PCLKSEL0 // Make pin selection for SPI. - // SCK0: P1.20 - // SSEL0: P1.21 - // MOSI0: P1.23 - // MISO0: P1.24 + // SCK0: P0.15 + // SSEL0: P0.16 + // MOSI0: P0.17 + // MISO0: P0.18 LPC_PINCON->PINSEL0 &= ~(0x3 << SCK0_BIT); LPC_PINCON->PINSEL0 |= (SCK0_FUNCTION << SCK0_BIT); @@ -143,7 +144,7 @@ void spi_init() #endif/*USE_CMSIS*/ // Configure SSEL pin: - LPC_GPIO1->FIODIR |= 1 << 21; // Set 1.21 in output mode + LPC_GPIO0->FIODIR |= 1 << 16; // Set P0.16 in output mode } @@ -203,29 +204,29 @@ void spi_read_write(uint8_t *tx_data, uint8_t *rx_data, size_t length) dst.callback = spi_mark_as_done; SPI_ClearIntPending(spi); - LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low + LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low spi_done = 0; SPI_ReadWrite(spi, &dst, SPI_TRANSFER_POLLING);//SPI_TRANSFER_INTERRUPT); - cli_write(">"); + // cli_write(">"); while (!(SPI_GetStatus(spi) & SPI_SPSR_SPIF)) { } //while(!spi_done) {} - cli_write("<"); + //cli_write("<"); - LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high + LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high #else/*USE_CMSIS*/ int i = 0; - cli_write(">>"); + // cli_write(">>"); - LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low + LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low for(; i < length; i++) { /* cli_write("w"); - LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low + LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low __delay(1 << 23); */ @@ -252,13 +253,15 @@ void spi_read_write(uint8_t *tx_data, uint8_t *rx_data, size_t length) /* cli_write("r"); - LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high + LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high __delay(1 << 23); */ } - LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high + LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high - cli_write("<<"); + //cli_write("<<"); #endif/*USE_CMSIS*/ } + +#endif/*0*/ diff --git a/firmware/drivers/ssp.c b/firmware/drivers/ssp.c new file mode 100644 index 0000000..ad2c6fe --- /dev/null +++ b/firmware/drivers/ssp.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * $Id:: ssp.c 5804 2010-12-04 00:32:12Z usb00423 $ + * Project: NXP LPC17xx SSP example + * + * Description: + * This file contains SSP code example which include SSP initialization, + * SSP interrupt handler, and APIs for SSP access. + * + **************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. +****************************************************************************/ +#include /* LPC17xx Peripheral Registers */ +#include "ssp.h" + +/* statistics of all the interrupts */ +volatile uint32_t interrupt0RxStat = 0; +volatile uint32_t interrupt0OverRunStat = 0; +volatile uint32_t interrupt0RxTimeoutStat = 0; +volatile uint32_t interrupt1RxStat = 0; +volatile uint32_t interrupt1OverRunStat = 0; +volatile uint32_t interrupt1RxTimeoutStat = 0; + +/***************************************************************************** +** Function name: SSP_IRQHandler +** +** Descriptions: SSP port is used for SPI communication. +** SSP interrupt handler +** The algorithm is, if RXFIFO is at least half full, +** start receive until it's empty; if TXFIFO is at least +** half empty, start transmit until it's full. +** This will maximize the use of both FIFOs and performance. +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void SSP0_IRQHandler(void) +{ + uint32_t regValue; + + regValue = LPC_SSP0->MIS; + if ( regValue & SSPMIS_RORMIS ) /* Receive overrun interrupt */ + { + interrupt0OverRunStat++; + LPC_SSP0->ICR = SSPICR_RORIC; /* clear interrupt */ + } + if ( regValue & SSPMIS_RTMIS ) /* Receive timeout interrupt */ + { + interrupt0RxTimeoutStat++; + LPC_SSP0->ICR = SSPICR_RTIC; /* clear interrupt */ + } + + /* please be aware that, in main and ISR, CurrentRxIndex and CurrentTxIndex + are shared as global variables. It may create some race condition that main + and ISR manipulate these variables at the same time. SSPSR_BSY checking (polling) + in both main and ISR could prevent this kind of race condition */ + if ( regValue & SSPMIS_RXMIS ) /* Rx at least half full */ + { + interrupt0RxStat++; /* receive until it's empty */ + } + return; +} + +/***************************************************************************** +** Function name: SSP_IRQHandler +** +** Descriptions: SSP port is used for SPI communication. +** SSP interrupt handler +** The algorithm is, if RXFIFO is at least half full, +** start receive until it's empty; if TXFIFO is at least +** half empty, start transmit until it's full. +** This will maximize the use of both FIFOs and performance. +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void SSP1_IRQHandler(void) +{ + uint32_t regValue; + + regValue = LPC_SSP1->MIS; + if ( regValue & SSPMIS_RORMIS ) /* Receive overrun interrupt */ + { + interrupt1OverRunStat++; + LPC_SSP1->ICR = SSPICR_RORIC; /* clear interrupt */ + } + if ( regValue & SSPMIS_RTMIS ) /* Receive timeout interrupt */ + { + interrupt1RxTimeoutStat++; + LPC_SSP1->ICR = SSPICR_RTIC; /* clear interrupt */ + } + + /* please be aware that, in main and ISR, CurrentRxIndex and CurrentTxIndex + are shared as global variables. It may create some race condition that main + and ISR manipulate these variables at the same time. SSPSR_BSY checking (polling) + in both main and ISR could prevent this kind of race condition */ + if ( regValue & SSPMIS_RXMIS ) /* Rx at least half full */ + { + interrupt1RxStat++; /* receive until it's empty */ + } + return; +} + +/***************************************************************************** +** Function name: SSP0_SSELToggle +** +** Descriptions: SSP0 CS manual set +** +** parameters: port num, toggle(1 is high, 0 is low) +** Returned value: None +** +*****************************************************************************/ +void SSP_SSELToggle( uint32_t portnum, uint32_t toggle ) +{ + if ( portnum == 0 ) + { + if ( !toggle ) + LPC_GPIO0->FIOCLR |= (0x1<<16); + else + LPC_GPIO0->FIOSET |= (0x1<<16); + } + else if ( portnum == 1 ) + { + if ( !toggle ) + LPC_GPIO0->FIOCLR |= (0x1<<6); + else + LPC_GPIO0->FIOSET |= (0x1<<6); + } + return; +} + +// Bent code: +// SPI power bit in PCONP register (see table 46) +#define PCSPI_BIT 8 + +// SPI clock bits (16 and 17) in PCLKSEL0 register (see table 40) +#define PCLK_SPI_BIT 16 + +typedef enum { + CCLK_4 = 0x0, // 00: PCLK_peripheral = CCLK/4 + CCLK_1 = 0x1, // 01: PCLK_peripheral = CCLK + CCLK_2 = 0x2, // 10: PCLK_peripheral = CCLK/2 + CCLK_8 = 0x3, // 11: PCLK_peripheral = CCLK/8 +} ClockDevisor; + +/***************************************************************************** +** Function name: SSPInit +** +** Descriptions: SSP port initialization routine +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void SSP0Init( void ) +{ + uint8_t i, Dummy=Dummy; + + /* Enable AHB clock to the SSP0. */ + //LPC_SC->PCONP |= (0x1<<21); + + /* Further divider is needed on SSP0 clock. Using default divided by 4 */ + //LPC_SC->PCLKSEL1 &= ~(0x3<<10); + + //Bent code: + // Power up the SPI bus. + // Remark: On reset, the SPI is enabled (PCSPI = 1). + LPC_SC->PCONP |= (1 << PCSPI_BIT); // set bit 8 in PCONP (PCSPI bit) + + ClockDevisor clk = CCLK_8; + LPC_SC->PCLKSEL0 &= ~(0x3 << PCLK_SPI_BIT); + LPC_SC->PCLKSEL0 |= ((clk & 0x3) << PCLK_SPI_BIT); // set bit 16 and 17 in PCLKSEL0 + + + /* P0.15~0.18 as SSP0 */ + LPC_PINCON->PINSEL0 &= ~(0x3UL<<30); + LPC_PINCON->PINSEL0 |= (0x2UL<<30); + LPC_PINCON->PINSEL1 &= ~((0x3<<0)|(0x3<<2)|(0x3<<4)); + LPC_PINCON->PINSEL1 |= ((0x2<<0)|(0x2<<2)|(0x2<<4)); + +#if !USE_CS + LPC_PINCON->PINSEL1 &= ~(0x3<<0); + LPC_GPIO0->FIODIR |= (0x1<<16); /* P0.16 defined as GPIO and Outputs */ +#endif + + /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */ + LPC_SSP0->CR0 = 0x0707; + + /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */ + LPC_SSP0->CPSR = 0x2; + + for ( i = 0; i < FIFOSIZE; i++ ) + { + Dummy = LPC_SSP0->DR; /* clear the RxFIFO */ + } + + /* Enable the SSP Interrupt */ + NVIC_EnableIRQ(SSP0_IRQn); + + /* Device select as master, SSP Enabled */ +#if LOOPBACK_MODE + LPC_SSP0->CR1 = SSPCR1_LBM | SSPCR1_SSE; +#else +#if SSP_SLAVE + /* Slave mode */ + if ( LPC_SSP0->CR1 & SSPCR1_SSE ) + { + /* The slave bit can't be set until SSE bit is zero. */ + LPC_SSP0->CR1 &= ~SSPCR1_SSE; + } + LPC_SSP0->CR1 = SSPCR1_MS; /* Enable slave bit first */ + LPC_SSP0->CR1 |= SSPCR1_SSE; /* Enable SSP */ +#else + /* Master mode */ + LPC_SSP0->CR1 = SSPCR1_SSE; +#endif +#endif + /* Set SSPINMS registers to enable interrupts */ + /* enable all error related interrupts */ + LPC_SSP0->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM; + return; +} + +/***************************************************************************** +** Function name: SSPInit +** +** Descriptions: SSP port initialization routine +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void SSP1Init( void ) +{ + uint8_t i, Dummy=Dummy; + + /* Enable AHB clock to the SSP1. */ + LPC_SC->PCONP |= (0x1<<10); + + /* Further divider is needed on SSP1 clock. Using default divided by 4 */ + LPC_SC->PCLKSEL0 &= ~(0x3<<20); + + /* P0.6~0.9 as SSP1 */ + LPC_PINCON->PINSEL0 &= ~((0x3<<12)|(0x3<<14)|(0x3<<16)|(0x3<<18)); + LPC_PINCON->PINSEL0 |= ((0x2<<12)|(0x2<<14)|(0x2<<16)|(0x2<<18)); + +#if !USE_CS + LPC_PINCON->PINSEL0 &= ~(0x3<<12); + LPC_GPIO0->FIODIR |= (0x1<<6); /* P0.6 defined as GPIO and Outputs */ +#endif + + /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */ + LPC_SSP1->CR0 = 0x0707; + + /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */ + LPC_SSP1->CPSR = 0x2; + + for ( i = 0; i < FIFOSIZE; i++ ) + { + Dummy = LPC_SSP1->DR; /* clear the RxFIFO */ + } + + /* Enable the SSP Interrupt */ + NVIC_EnableIRQ(SSP1_IRQn); + + /* Device select as master, SSP Enabled */ +#if LOOPBACK_MODE + LPC_SSP1->CR1 = SSPCR1_LBM | SSPCR1_SSE; +#else +#if SSP_SLAVE + /* Slave mode */ + if ( LPC_SSP1->CR1 & SSPCR1_SSE ) + { + /* The slave bit can't be set until SSE bit is zero. */ + LPC_SSP1->CR1 &= ~SSPCR1_SSE; + } + LPC_SSP1->CR1 = SSPCR1_MS; /* Enable slave bit first */ + LPC_SSP1->CR1 |= SSPCR1_SSE; /* Enable SSP */ +#else + /* Master mode */ + LPC_SSP1->CR1 = SSPCR1_SSE; +#endif +#endif + /* Set SSPINMS registers to enable interrupts */ + /* enable all error related interrupts */ + LPC_SSP1->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM; + return; +} + +/***************************************************************************** +** Function name: SSPSend +** +** Descriptions: Send a block of data to the SSP port, the +** first parameter is the buffer pointer, the 2nd +** parameter is the block length. +** +** parameters: buffer pointer, and the block length +** Returned value: None +** +*****************************************************************************/ +void SSPSend( uint32_t portnum, uint8_t *buf, uint32_t Length ) +{ + uint32_t i; + uint8_t Dummy = Dummy; + + for ( i = 0; i < Length; i++ ) + { + if ( portnum == 0 ) + { + /* Move on only if NOT busy and TX FIFO not full. */ + while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF ); + LPC_SSP0->DR = *buf; + buf++; +#if !LOOPBACK_MODE + while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); + /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO + on MISO. Otherwise, when SSP0Receive() is called, previous data byte + is left in the FIFO. */ + Dummy = LPC_SSP0->DR; +#else + /* Wait until the Busy bit is cleared. */ + while ( LPC_SSP0->SR & SSPSR_BSY ); +#endif + } + else if ( portnum == 1 ) + { + /* Move on only if NOT busy and TX FIFO not full. */ + while ( (LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF ); + LPC_SSP1->DR = *buf; + buf++; +#if !LOOPBACK_MODE + while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); + /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO + on MISO. Otherwise, when SSP0Receive() is called, previous data byte + is left in the FIFO. */ + Dummy = LPC_SSP1->DR; +#else + /* Wait until the Busy bit is cleared. */ + while ( LPC_SSP1->SR & SSPSR_BSY ); +#endif + } + } + return; +} + +/***************************************************************************** +** Function name: SSPReceive +** Descriptions: the module will receive a block of data from +** the SSP, the 2nd parameter is the block +** length. +** parameters: buffer pointer, and block length +** Returned value: None +** +*****************************************************************************/ +void SSPReceive( uint32_t portnum, uint8_t *buf, uint32_t Length ) +{ + uint32_t i; + + for ( i = 0; i < Length; i++ ) + { + /* As long as Receive FIFO is not empty, I can always receive. */ + /* If it's a loopback test, clock is shared for both TX and RX, + no need to write dummy byte to get clock to get the data */ + /* if it's a peer-to-peer communication, SSPDR needs to be written + before a read can take place. */ + if ( portnum == 0 ) + { +#if !LOOPBACK_MODE +#if SSP_SLAVE + while ( !(LPC_SSP0->SR & SSPSR_RNE) ); +#else + LPC_SSP0->DR = 0xFF; + /* Wait until the Busy bit is cleared */ + while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); +#endif +#else + while ( !(LPC_SSP0->SR & SSPSR_RNE) ); +#endif + *buf++ = LPC_SSP0->DR; + } + else if ( portnum == 1 ) + { +#if !LOOPBACK_MODE +#if SSP_SLAVE + while ( !(LPC_SSP1->SR & SSPSR_RNE) ); +#else + LPC_SSP1->DR = 0xFF; + /* Wait until the Busy bit is cleared */ + while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); +#endif +#else + while ( !(LPC_SSP1->SR & SSPSR_RNE) ); +#endif + *buf++ = LPC_SSP1->DR; + } + } + return; +} + +/****************************************************************************** +** End Of File +******************************************************************************/ + diff --git a/firmware/drivers/ssp.h b/firmware/drivers/ssp.h new file mode 100644 index 0000000..c543422 --- /dev/null +++ b/firmware/drivers/ssp.h @@ -0,0 +1,121 @@ +/**************************************************************************** + * $Id:: ssp.h 5741 2010-11-30 23:13:47Z usb00423 $ + * Project: NXP LPC17xx SSP example + * + * Description: + * This file contains SSP code header definition. + * + **************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. +****************************************************************************/ +#ifndef __SSP_H__ +#define __SSP_H__ + +/* There are there modes in SSP: loopback, master or slave. */ +/* Here are the combination of all the tests. +(1) LOOPBACK test: LOOPBACK_MODE=1, TX_RX_ONLY=0, USE_CS=1; +(2) Serial EEPROM test: LOOPBACK_MODE=0, TX_RX_ONLY=0, USE_CS=0; (default) +(3) TX(Master) Only: LOOPBACK_MODE=0, SSP_SLAVE=0, TX_RX_ONLY=1, USE_CS=1; +(4) RX(Slave) Only: LOOPBACK_MODE=0, SSP_SLAVE=1, TX_RX_ONLY=0, USE_CS=1 */ + +#define LOOPBACK_MODE 0 /* 1 is loopback, 0 is normal operation. */ +#define SSP_SLAVE 0 /* 1 is SLAVE mode, 0 is master mode */ +#define TX_RX_ONLY 0 /* 1 is TX or RX only depending on SSP_SLAVE + flag, 0 is either loopback mode or communicate + with a serial EEPROM. */ + +/* if USE_CS is zero, set SSEL as GPIO that you have total control of the sequence */ +/* When test serial SEEPROM(LOOPBACK_MODE=0, TX_RX_ONLY=0), set USE_CS to 0. */ +/* When LOOPBACK_MODE=1 or TX_RX_ONLY=1, set USE_CS to 1. */ + +#define USE_CS 0 + +/* SPI read and write buffer size */ +#define SSP_BUFSIZE 16 +#define FIFOSIZE 8 + +#define DELAY_COUNT 10 +#define MAX_TIMEOUT 0xFF + +/* Port0.2 is the SSP select pin */ +#define SSP0_SEL (1 << 2) + +/* SSP Status register */ +#define SSPSR_TFE (1 << 0) +#define SSPSR_TNF (1 << 1) +#define SSPSR_RNE (1 << 2) +#define SSPSR_RFF (1 << 3) +#define SSPSR_BSY (1 << 4) + +/* SSP CR0 register */ +#define SSPCR0_DSS (1 << 0) +#define SSPCR0_FRF (1 << 4) +#define SSPCR0_SPO (1 << 6) +#define SSPCR0_SPH (1 << 7) +#define SSPCR0_SCR (1 << 8) + +/* SSP CR1 register */ +#define SSPCR1_LBM (1 << 0) +#define SSPCR1_SSE (1 << 1) +#define SSPCR1_MS (1 << 2) +#define SSPCR1_SOD (1 << 3) + +/* SSP Interrupt Mask Set/Clear register */ +#define SSPIMSC_RORIM (1 << 0) +#define SSPIMSC_RTIM (1 << 1) +#define SSPIMSC_RXIM (1 << 2) +#define SSPIMSC_TXIM (1 << 3) + +/* SSP0 Interrupt Status register */ +#define SSPRIS_RORRIS (1 << 0) +#define SSPRIS_RTRIS (1 << 1) +#define SSPRIS_RXRIS (1 << 2) +#define SSPRIS_TXRIS (1 << 3) + +/* SSP0 Masked Interrupt register */ +#define SSPMIS_RORMIS (1 << 0) +#define SSPMIS_RTMIS (1 << 1) +#define SSPMIS_RXMIS (1 << 2) +#define SSPMIS_TXMIS (1 << 3) + +/* SSP0 Interrupt clear register */ +#define SSPICR_RORIC (1 << 0) +#define SSPICR_RTIC (1 << 1) + +/* ATMEL SEEPROM command set */ +#define WREN 0x06 /* MSB A8 is set to 0, simplifying test */ +#define WRDI 0x04 +#define RDSR 0x05 +#define WRSR 0x01 +#define READ 0x03 +#define WRITE 0x02 + +/* RDSR status bit definition */ +#define RDSR_RDY 0x01 +#define RDSR_WEN 0x02 + +/* If RX_INTERRUPT is enabled, the SSP RX will be handled in the ISR +SSPReceive() will not be needed. */ +extern void SSP0_IRQHandler (void); +extern void SSP1_IRQHandler (void); +extern void SSP_SSELToggle( uint32_t portnum, uint32_t toggle ); +extern void SSP0Init( void ); +extern void SSP1Init( void ); +extern void SSP2Init( void ); +extern void SSPSend( uint32_t portnum, uint8_t *Buf, uint32_t Length ); +extern void SSPReceive( uint32_t portnum, uint8_t *buf, uint32_t Length ); + +#endif /* __SSP_H__ */ +/***************************************************************************** +** End Of File +******************************************************************************/ + diff --git a/firmware/drivers/timer.c b/firmware/drivers/timer.c new file mode 100644 index 0000000..ed9680b --- /dev/null +++ b/firmware/drivers/timer.c @@ -0,0 +1,572 @@ +/**************************************************************************** + * $Id:: timer.c 5823 2010-12-07 19:01:00Z usb00423 $ + * Project: NXP LPC17xx Timer for PWM example + * + * Description: + * This file contains timer code example which include timer + * initialization, timer interrupt handler, and APIs for timer access. + * + **************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. +****************************************************************************/ +#include + +//#include "lpc_types.h" +#define FALSE 0 +#define TRUE 1 + +#include "timer.h" + +volatile uint32_t timer0_m0_counter = 0; +volatile uint32_t timer1_m0_counter = 0; +volatile uint32_t timer2_m0_counter = 0; +volatile uint32_t timer3_m0_counter = 0; +volatile uint32_t timer0_m1_counter = 0; +volatile uint32_t timer1_m1_counter = 0; +volatile uint32_t timer2_m1_counter = 0; +volatile uint32_t timer3_m1_counter = 0; + +volatile uint32_t timer0_capture0 = 0; +volatile uint32_t timer1_capture0 = 0; +volatile uint32_t timer2_capture0 = 0; +volatile uint32_t timer3_capture0 = 0; +volatile uint32_t timer0_capture1 = 0; +volatile uint32_t timer1_capture1 = 0; +volatile uint32_t timer2_capture1 = 0; +volatile uint32_t timer3_capture1 = 0; + +/***************************************************************************** +** Function name: delayMs +** +** Descriptions: Start the timer delay in milo seconds +** until elapsed +** +** parameters: timer number, Delay value in milo second +** +** Returned value: None +** +*****************************************************************************/ +void delayMs(uint8_t timer_num, uint32_t delayInMs) +{ + if ( timer_num == 0 ) + { + LPC_TIM0->TCR = 0x02; /* reset timer */ + LPC_TIM0->PR = 0x00; /* set prescaler to zero */ + LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time + LPC_TIM0->IR = 0xff; /* reset all interrrupts */ + LPC_TIM0->MCR = 0x04; /* stop timer on match */ + LPC_TIM0->TCR = 0x01; /* start timer */ + + /* wait until delay time has elapsed */ + while (LPC_TIM0->TCR & 0x01); + + } + else if ( timer_num == 1 ) + { + LPC_TIM1->TCR = 0x02; /* reset timer */ + LPC_TIM1->PR = 0x00; /* set prescaler to zero */ + LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time + LPC_TIM1->IR = 0xff; /* reset all interrrupts */ + LPC_TIM1->MCR = 0x04; /* stop timer on match */ + LPC_TIM1->TCR = 0x01; /* start timer */ + + /* wait until delay time has elapsed */ + while (LPC_TIM1->TCR & 0x01); + } + + else if ( timer_num == 2 ) + { + LPC_TIM2->TCR = 0x02; /* reset timer */ + LPC_TIM2->PR = 0x00; /* set prescaler to zero */ + LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time + LPC_TIM2->IR = 0xff; /* reset all interrrupts */ + LPC_TIM2->MCR = 0x04; /* stop timer on match */ + LPC_TIM2->TCR = 0x01; /* start timer */ + + /* wait until delay time has elapsed */ + while (LPC_TIM2->TCR & 0x01); + } + + else if ( timer_num == 3 ) + { + LPC_TIM3->TCR = 0x02; /* reset timer */ + LPC_TIM3->PR = 0x00; /* set prescaler to zero */ + LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time + LPC_TIM3->IR = 0xff; /* reset all interrrupts */ + LPC_TIM3->MCR = 0x04; /* stop timer on match */ + LPC_TIM3->TCR = 0x01; /* start timer */ + + /* wait until delay time has elapsed */ + while (LPC_TIM3->TCR & 0x01); + } + return; +} + +/****************************************************************************** +** Function name: Timer0_IRQHandler +** +** Descriptions: Timer/Counter 0 interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void TIMER0_interrupt (void) +{ + if ( LPC_TIM0->IR & (0x1<<0) ) + { + LPC_TIM0->IR = 0x1<<0; /* clear interrupt flag */ + timer0_m0_counter++; + } + if ( LPC_TIM0->IR & (0x1<<1) ) + { + LPC_TIM0->IR = 0x1<<1; /* clear interrupt flag */ + timer0_m1_counter++; + } + if ( LPC_TIM0->IR & (0x1<<4) ) + { + LPC_TIM0->IR = 0x1<<4; /* clear interrupt flag */ + timer0_capture0++; + } + if ( LPC_TIM0->IR & (0x1<<5) ) + { + LPC_TIM0->IR = 0x1<<5; /* clear interrupt flag */ + timer0_capture1++; + } + return; +} + +/****************************************************************************** +** Function name: Timer1_IRQHandler +** +** Descriptions: Timer/Counter 1 interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void TIMER1_interrupt (void) +{ + if ( LPC_TIM1->IR & (0x1<<0) ) + { + LPC_TIM1->IR = 0x1<<0; /* clear interrupt flag */ + timer1_m0_counter++; + } + if ( LPC_TIM1->IR & (0x1<<1) ) + { + LPC_TIM1->IR = 0x1<<1; /* clear interrupt flag */ + timer1_m1_counter++; + } + if ( LPC_TIM1->IR & (0x1<<4) ) + { + LPC_TIM1->IR = 0x1<<4; /* clear interrupt flag */ + timer1_capture0++; + } + if ( LPC_TIM1->IR & (0x1<<5) ) + { + LPC_TIM1->IR = 0x1<<5; /* clear interrupt flag */ + timer1_capture1++; + } + return; +} + +/****************************************************************************** +** Function name: Timer2_IRQHandler +** +** Descriptions: Timer/Counter 2 interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void TIMER2_interrupt (void) +{ + if ( LPC_TIM2->IR & (0x1<<0) ) + { + LPC_TIM2->IR = 0x1<<0; /* clear interrupt flag */ + timer2_m0_counter++; + } + if ( LPC_TIM2->IR & (0x1<<1) ) + { + LPC_TIM2->IR = 0x1<<1; /* clear interrupt flag */ + timer2_m1_counter++; + } + if ( LPC_TIM2->IR & (0x1<<4) ) + { + LPC_TIM2->IR = 0x1<<4; /* clear interrupt flag */ + timer2_capture0++; + } + if ( LPC_TIM2->IR & (0x1<<5) ) + { + LPC_TIM2->IR = 0x1<<5; /* clear interrupt flag */ + timer2_capture1++; + } + return; +} + +/****************************************************************************** +** Function name: Timer3_IRQHandler +** +** Descriptions: Timer/Counter 3 interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void TIMER3_interrupt (void) +{ + if ( LPC_TIM3->IR & (0x1<<0) ) + { + LPC_TIM3->IR = 0x1<<0; /* clear interrupt flag */ + timer3_m0_counter++; + } + if ( LPC_TIM3->IR & (0x1<<1) ) + { + LPC_TIM3->IR = 0x1<<1; /* clear interrupt flag */ + timer3_m1_counter++; + } + if ( LPC_TIM3->IR & (0x1<<4) ) + { + LPC_TIM3->IR = 0x1<<4; /* clear interrupt flag */ + timer3_capture0++; + } + if ( LPC_TIM3->IR & (0x1<<5) ) + { + LPC_TIM3->IR = 0x1<<5; /* clear interrupt flag */ + timer3_capture1++; + } + return; +} + +/****************************************************************************** +** Function name: enable_timer +** +** Descriptions: Enable timer +** +** parameters: timer number: 0 or 1 or 2 or 3 +** Returned value: None +** +******************************************************************************/ +void enable_timer( uint8_t timer_num ) +{ + if ( timer_num == 0 ) + { + LPC_TIM0->TCR = 1; + } + else if ( timer_num == 1 ) + { + LPC_TIM1->TCR = 1; + } + else if ( timer_num == 2 ) + { + LPC_TIM2->TCR = 1; + } + else if ( timer_num == 3 ) + { + LPC_TIM3->TCR = 1; + } + return; +} + +/****************************************************************************** +** Function name: disable_timer +** +** Descriptions: Disable timer +** +** parameters: timer number: 0 or 1 oe 2 or 3 +** Returned value: None +** +******************************************************************************/ +void disable_timer( uint8_t timer_num ) +{ + if ( timer_num == 0 ) + { + LPC_TIM0->TCR = 0; + } + else if ( timer_num == 1 ) + { + LPC_TIM1->TCR = 0; + } + else if ( timer_num == 2 ) + { + LPC_TIM2->TCR = 0; + } + else if ( timer_num == 3 ) + { + LPC_TIM2->TCR = 0; + } + return; +} + +/****************************************************************************** +** Function name: reset_timer +** +** Descriptions: Reset timer +** +** parameters: timer number: 0 or 1 or 2 or 3 +** Returned value: None +** +******************************************************************************/ +void reset_timer( uint8_t timer_num ) +{ + uint32_t regVal; + + if ( timer_num == 0 ) + { + regVal = LPC_TIM0->TCR; + regVal |= 0x02; + LPC_TIM0->TCR = regVal; + } + else if ( timer_num == 1 ) + { + regVal = LPC_TIM1->TCR; + regVal |= 0x02; + LPC_TIM1->TCR = regVal; + } + else if ( timer_num == 2 ) + { + regVal = LPC_TIM2->TCR; + regVal |= 0x02; + LPC_TIM2->TCR = regVal; + } + else if ( timer_num == 3 ) + { + regVal = LPC_TIM3->TCR; + regVal |= 0x02; + LPC_TIM3->TCR = regVal; + } + return; +} + +/****************************************************************************** +** Function name: init_timer +** +** Descriptions: Initialize timer, set timer interval, reset timer, +** install timer interrupt handler +** +** parameters: timer number and timer interval +** Returned value: true or false, if the interrupt handler can't be +** installed, return false. +** +******************************************************************************/ +uint32_t TimerInit( uint8_t timer_num, uint32_t TimerInterval ) +{ + uint32_t pclkdiv, pclk; + (void)pclk; + + if ( timer_num == 0 ) + { + timer0_m0_counter = 0; + timer0_m1_counter = 0; + timer0_capture0 = 0; + timer0_capture1 = 0; + LPC_SC->PCONP |= (0x01<<1); +#if TIMER_MATCH + LPC_PINCON->PINSEL3 &= ~((0x3<<24)|(0x3<<26)); + LPC_PINCON->PINSEL3 |= ((0x3<<24)|(0x3<<26)); +#else + LPC_PINCON->PINSEL3 &= ~((0x3<<20)|(0x3<<22)); + LPC_PINCON->PINSEL3 |= ((0x3<<20)|(0x3<<22)); +#endif + LPC_TIM0->IR = 0x0F; /* Clear MATx interrupt include DMA request */ + + /* By default, the PCLKSELx value is zero, thus, the PCLK for + all the peripherals is 1/4 of the SystemCoreClock. */ + /* Bit 2~3 is for TIMER0 */ + pclkdiv = (LPC_SC->PCLKSEL0 >> 2) & 0x03; + switch ( pclkdiv ) + { + case 0x00: + default: + pclk = SystemCoreClock/4; + break; + case 0x01: + pclk = SystemCoreClock; + break; + case 0x02: + pclk = SystemCoreClock/2; + break; + case 0x03: + pclk = SystemCoreClock/8; + break; + } + LPC_TIM0->PR = 0; + + LPC_TIM0->MR0 = TimerInterval/4; + LPC_TIM0->MR1 = TimerInterval/4; +#if TIMER_MATCH + LPC_TIM0->EMR &= ~(0xFF<<4); + LPC_TIM0->EMR |= ((0x3<<4)|(0x3<<6)); +#else + /* Capture 0 and 1 on rising edge, interrupt enable. */ + LPC_TIM0->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); +#endif + LPC_TIM0->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ + NVIC_EnableIRQ(TIMER0_IRQn); + return (TRUE); + } + else if ( timer_num == 1 ) + { + timer1_m0_counter = 0; + timer1_m1_counter = 0; + timer1_capture0 = 0; + timer1_capture1 = 0; + LPC_SC->PCONP |= (0x1<<2); +#if TIMER_MATCH + LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); + LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); +#else + LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); + LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); +#endif + LPC_TIM1->IR = 0x0F; /* Clear MATx interrupt include DMA request */ + /* By default, the PCLKSELx value is zero, thus, the PCLK for + all the peripherals is 1/4 of the SystemCoreClock. */ + /* Bit 4~5 is for TIMER0 */ + pclkdiv = (LPC_SC->PCLKSEL0 >> 4) & 0x03; + switch ( pclkdiv ) + { + case 0x00: + default: + pclk = SystemCoreClock/4; + break; + case 0x01: + pclk = SystemCoreClock; + break; + case 0x02: + pclk = SystemCoreClock/2; + break; + case 0x03: + pclk = SystemCoreClock/8; + break; + } + LPC_TIM1->PR = 0; + LPC_TIM1->MR0 = TimerInterval/4; + LPC_TIM1->MR1 = TimerInterval/4; +#if TIMER_MATCH + LPC_TIM1->EMR &= ~(0xFF<<4); + LPC_TIM1->EMR |= ((0x3<<4)|(0x3<<6)); +#else + /* Capture 0/1 on rising edge, interrupt enable. */ + LPC_TIM1->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); +#endif + LPC_TIM1->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ + NVIC_EnableIRQ(TIMER1_IRQn); + return (TRUE); + } + + else if ( timer_num == 2 ) + { + timer2_m0_counter = 0; + timer2_m1_counter = 0; + timer2_capture0 = 0; + timer2_capture1 = 0; + LPC_SC->PCONP |= (0x1<<22); + #if TIMER_MATCH + LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); + LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); + #else + LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); + LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); + #endif + LPC_TIM2->IR = 0x0F; /* Clear MATx interrupt include DMA request */ + /* By default, the PCLKSELx value is zero, thus, the PCLK for + all the peripherals is 1/4 of the SystemCoreClock. */ + /* Bit 12~13 is for TIMER2 */ + pclkdiv = (LPC_SC->PCLKSEL1 >> 12) & 0x03; + switch ( pclkdiv ) + { + case 0x00: + default: + pclk = SystemCoreClock/4; + break; + case 0x01: + pclk = SystemCoreClock; + break; + case 0x02: + pclk = SystemCoreClock/2; + break; + case 0x03: + pclk = SystemCoreClock/8; + break; + } + LPC_TIM2->PR = 0; + LPC_TIM2->MR0 = TimerInterval/4; + LPC_TIM2->MR1 = TimerInterval/4; + #if TIMER_MATCH + LPC_TIM2->EMR &= ~(0xFF<<4); + LPC_TIM2->EMR |= ((0x3<<4)|(0x3<<6)); + #else + /* Capture 0/1 on rising edge, interrupt enable. */ + LPC_TIM2->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); + #endif + LPC_TIM2->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ + NVIC_EnableIRQ(TIMER2_IRQn); + return (TRUE); + } + + else if ( timer_num == 3 ) + { + timer3_m0_counter = 0; + timer3_m1_counter = 0; + timer3_capture0 = 0; + timer3_capture1 = 0; + LPC_SC->PCONP |= (0x1<<23); + #if TIMER_MATCH + LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); + LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); + #else + LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); + LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); + #endif + LPC_TIM3->IR = 0x0F; /* Clear MATx interrupt include DMA request */ + /* By default, the PCLKSELx value is zero, thus, the PCLK for + all the peripherals is 1/4 of the SystemCoreClock. */ + /* Bit 14~15 is for TIMER3 */ + pclkdiv = (LPC_SC->PCLKSEL1 >> 14) & 0x03; + switch ( pclkdiv ) + { + case 0x00: + default: + pclk = SystemCoreClock/4; + break; + case 0x01: + pclk = SystemCoreClock; + break; + case 0x02: + pclk = SystemCoreClock/2; + break; + case 0x03: + pclk = SystemCoreClock/8; + break; + } + LPC_TIM3->PR = 0; + LPC_TIM3->MR0 = TimerInterval/4; + LPC_TIM3->MR1 = TimerInterval/4; + #if TIMER_MATCH + LPC_TIM3->EMR &= ~(0xFF<<4); + LPC_TIM3->EMR |= ((0x3<<4)|(0x3<<6)); + #else + /* Capture 0/1 on rising edge, interrupt enable. */ + LPC_TIM3->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); + #endif + LPC_TIM3->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ + NVIC_EnableIRQ(TIMER3_IRQn); + return (TRUE); + } + + return (FALSE); +} + +/****************************************************************************** +** End Of File +******************************************************************************/ diff --git a/firmware/drivers/timer.h b/firmware/drivers/timer.h new file mode 100644 index 0000000..1f16976 --- /dev/null +++ b/firmware/drivers/timer.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * $Id:: timer.h 5823 2010-12-07 19:01:00Z usb00423 $ + * Project: NXP LPC17xx Timer example + * + * Description: + * This file contains Timer code header definition. + * + **************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. +****************************************************************************/ +#ifndef __TIMER_H +#define __TIMER_H + +/* The test is either MAT_OUT or CAP_IN. Default is MAT_OUT. */ +/* If running DMA test, External match is not needed to trigger DMA, but still +set timer as MATx instead of CAPx. */ +#define TIMER_MATCH 1 + +/* TIME_INTERVALmS is a value to load the timer match register with + to get a 1 mS delay */ +#define TIME_INTERVALmS 1000 + +#define TIME_INTERVAL (9000000/100 - 1) + +extern void delayMs(uint8_t timer_num, uint32_t delayInMs); +extern uint32_t TimerInit( uint8_t timer_num, uint32_t timerInterval ); +extern void enable_timer( uint8_t timer_num ); +extern void disable_timer( uint8_t timer_num ); +extern void reset_timer( uint8_t timer_num ); +extern void TIMER0_interrupt (void); +extern void TIMER1_interrupt (void); +extern void TIMER2_interrupt (void); +extern void TIMER3_interrupt (void); + +#endif /* end __TIMER_H */ +/***************************************************************************** +** End Of File +******************************************************************************/ diff --git a/firmware/drivers/wm8523.c b/firmware/drivers/wm8523.c index 08b8d97..f8cad99 100644 --- a/firmware/drivers/wm8523.c +++ b/firmware/drivers/wm8523.c @@ -26,6 +26,8 @@ */ #include "wm8523.h" +#if 1 + #include #include @@ -45,7 +47,7 @@ typedef union { void WM8523_init() { - cli_write("sizeof: %d", sizeof(WM8523_transfer_t)); + //cli_write("sizeof: %d", sizeof(WM8523_transfer_t)); spi_init(); } @@ -87,9 +89,11 @@ To use volume update in software control mode, I2C mode must be used. */ void WM8523_configure() { - spi_configure(); + // spi_init(); uint16_t id = WM8523_read(0); // Read chip id from reg0. - - cli_write("=%d=", id); // should be 34595 (0x8523) + (void)id; + // cli_write("=%d=", id); // should be 34595 (0x8523) } + +#endif/*0*/ diff --git a/firmware/src/p2m.c b/firmware/src/p2m.c index 11fe393..d44a01c 100644 --- a/firmware/src/p2m.c +++ b/firmware/src/p2m.c @@ -6,9 +6,11 @@ #include -//#define SPI -#define IRQ_BLINKY +//#define IRQ_BLINKY //#define BLINKY +//#define BLINKY +//#define WM8523 +#define SPI #ifdef DMA @@ -71,7 +73,7 @@ int main (void) } -#endif +#endif/*IRQ_BLINKY*/ #ifdef BLINKY @@ -90,7 +92,7 @@ int main (void) } -#endif +#endif/*BLINKY*/ #ifdef UART @@ -130,9 +132,9 @@ int main (void) } } -#endif +#endif/*UART*/ -#ifdef SPI +#ifdef WM8523 #include #include @@ -145,24 +147,146 @@ int main (void) LED_Init(); - cli_init(); - - cli_write("init"); - _delay(1 << 22); WM8523_init(); - cli_write("pre"); - _delay(1 << 22); WM8523_configure(); - cli_write("post"); + // Indicate that we didn't crash before the end... + int i = 0; + while(1) { + LED_toggle(); + _delay(1 << 21); + i = 1 - i; + } } -#endif +#endif/*WM8523*/ + +#ifdef SPI +// 1. Introduction +/* + SPI is one of the most used serial interfaces on PCB level. This tutorial + explains how to use SPI to read or write data. For SPI the SPI library is + required. It can be downloaded from our repository. The library provides + commands for communicating over SPI. +*/ + +// 2. Includes +#include +//#include "lpc_types.h" +#include +#include +#include +#include + +typedef unsigned char uint8_t; + +int main (void) +{ + LED_Init(); // Bent code + + // 3. Initializing + /* + SPI uses 4 IO pins, 1 clock, 1 MOSI, data from master to slave, 1 MISO, + data from slave to master and one Chip select pin. Every SPI IC has a Chip + Select pin, when the pin is low that IC will be selected to communicate + with. Every SPI IC that has a high value on the Chip Select pin will ignore + all signals on their data pins. 1 normal IO pin is used for the Chip Select, + the clock; MOSI and MISO are SPI pins. Any IO pin can be used for Chip + Select, For the tutorial pin 0.0 is used. + The timer has to be initialized to use it for delays and the GPIO pin for + Chip Select has to be initialized as output and made high, the code for + that is: + */ + // TimerInit(0, 1000); + + GPIOSetDir(0, 16, 1); + GPIOSetValue(0, 16, 1); + + /* + There are 2 SPI channels, SSP0 and SSP1. SSP0 uses pin 0.15 for the clock; + pin 0.17 for MISO and pin 0.18 for MOSI. SSP1 uses pin 0.7 for the clock; + pin 0.8 for MISO and pin 0.9 for MOSI. To initialize a SPI port the + command SSP*channelno*init(); is used. To initialize SPI channel 1 the + command is: + */ + SSP0Init(); + + /* + Some variables are also needed. SPI needs 2 array buffers, one for data + that has to be send trough the SPI slave and one for data received from + the SPI slave. Also its recommended to declare a variable with the value + of the SPI channel that is used: + */ + uint8_t src_addr[16]; //16 byte Write buffer + uint8_t dest_addr[16]; //16 byte Read buffer + uint8_t portnum = 0; + + // 4. Write data to SPI + /* + First the Chip Select has to be made low with the GPIOSetValue command: + GPIOSetValue(0, 0, 0;) + The data that has to be written should be placed in the src_addr array that + was declared earlier. To write 5 bytes of data (0x48, 0x65, 0x6c, 0x6c, + 0x6f the ascii code for Hello) place the hex data in the buffer array: + */ + + GPIOSetValue(0, 16, 0); + + src_addr[0] = 0x1 << 7; + src_addr[1] = 0xff; + src_addr[2] = 0xff; + + /* + When the data is stored in the array all that is left is start the SPI data + transmission with the SSPSend( portnum, (uint8_t *)src_addr, datanumbers); + portnum is the used SPI port, (uint8_t *)src_addr is the send buffer, + datanumbers is the amount of databytes to be send. The command needed to + send the 5 databytes declared above is: + */ + SSPSend(portnum, (uint8_t *)src_addr, 1); + + /* + After the data is send the Chip Select pin needs to be made high again with + the command GPIOSetValue(0, 0, 1); . Also a small delay can be needed for + some SPI IC’s, 1 millisecond is enough most of the time, the command for a + small delay is: delayMs(0, 1); + */ + // delayMs(0, 1); + + // GPIOSetValue(0, 16, 1); + + // 5. Read data from SPI + /* + To read data the Chip Select has to be made low with GPIOSetValue(0,0,0); . + To read data from SPI the command SSPReceive(portnum, (uint8_t *)dest_addr, + datanumbers); is used. Portnum is the used SPI port, (uint8_t *)dest_addr + is the receive buffer, datanumbers is the amount of databytes that have to + be read. A command to read 4 databytes is: + */ + // GPIOSetValue(0, 16, 0); + + SSPReceive(portnum, (uint8_t *)dest_addr, 3); + + GPIOSetValue(0, 16, 1); + /* + The 4 databytes are now stored in dest_addr[0] to dest_addr[3] + */ + + // Indicate that we didn't crash before the end... + int i = 0; + while(1) { + LED_toggle(); + _delay(1 << 21); + i = 1 - i; + } +} + +#endif/*SPI*/ void _delay(uint32_t del) { -- cgit v1.2.3