From 2b9ef9759bc7dcc38b465905dd226414d519804c Mon Sep 17 00:00:00 2001 From: BIITER Date: Fri, 8 Apr 2011 19:43:52 +0200 Subject: [PATCH] Added ADC and I/O read. --- firmware/src/LPC13xx.h | 2 +- firmware/src/adc.c | 274 ++++++++++++++++++++++++++++++++++ firmware/src/adc.h | 44 ++++++ firmware/src/edubrm.c | 55 +++++++ firmware/src/edubrm.h | 1 + firmware/src/gpio.h | 9 +- firmware/src/ssp.c | 2 +- firmware/src/usbhidrom_main.c | 28 ++-- 8 files changed, 391 insertions(+), 24 deletions(-) create mode 100644 firmware/src/adc.c create mode 100644 firmware/src/adc.h diff --git a/firmware/src/LPC13xx.h b/firmware/src/LPC13xx.h index 81a9b5f..d7582e5 100644 --- a/firmware/src/LPC13xx.h +++ b/firmware/src/LPC13xx.h @@ -241,7 +241,7 @@ typedef struct __IO uint32_t JTAG_TCK_PIO0_10; __IO uint32_t PIO1_10; __IO uint32_t PIO2_11; - __IO uint32_t JTAG_TDI_PIO0_11; + __IO uint32_t PIO0_11; // JTAG_TDI_PIO0_11 __IO uint32_t JTAG_TMS_PIO1_0; __IO uint32_t JTAG_TDO_PIO1_1; diff --git a/firmware/src/adc.c b/firmware/src/adc.c new file mode 100644 index 0000000..734d58f --- /dev/null +++ b/firmware/src/adc.c @@ -0,0 +1,274 @@ +/**************************************************************************** + * $Id:: adc.c 3633 2010-06-01 23:03:16Z usb00423 $ + * Project: NXP LPC13xx ADC example + * + * Description: + * This file contains ADC code example which include ADC + * initialization, ADC interrupt handler, and APIs for ADC + * reading. + * + **************************************************************************** + * 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 "LPC13xx.h" /* LPC13xx Peripheral Registers */ +#include "adc.h" + +volatile uint32_t ADCValue[ADC_NUM]; +volatile uint32_t ADCIntDone = 0; + +#if BURST_MODE +volatile uint32_t channel_flag; +#endif + +#if ADC_INTERRUPT_FLAG +/****************************************************************************** +** Function name: ADC_IRQHandler +** +** Descriptions: ADC interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void ADC_IRQHandler (void) +{ + uint32_t regVal; + + regVal = LPC_ADC->STAT; /* Read ADC will clear the interrupt */ + if ( regVal & 0x0000FF00 ) /* check OVERRUN error first */ + { + regVal = (regVal & 0x0000FF00) >> 0x08; + /* if overrun, just read ADDR to clear */ + /* regVal variable has been reused. */ + switch ( regVal ) + { + case 0x01: + regVal = LPC_ADC->DR0; + break; + case 0x02: + regVal = LPC_ADC->DR1; + break; + case 0x04: + regVal = LPC_ADC->DR2; + break; + case 0x08: + regVal = LPC_ADC->DR3; + break; + case 0x10: + regVal = LPC_ADC->DR4; + break; + case 0x20: + regVal = LPC_ADC->DR5; + break; + case 0x40: + regVal = LPC_ADC->DR6; + break; + case 0x80: + regVal = LPC_ADC->DR7; + break; + default: + break; + } + LPC_ADC->CR &= 0xF8FFFFFF; /* stop ADC now */ + ADCIntDone = 1; + return; + } + + if ( regVal & ADC_ADINT ) + { + switch ( regVal & 0xFF ) /* check DONE bit */ + { + case 0x01: + ADCValue[0] = ( LPC_ADC->DR0 >> 6 ) & 0x3FF; + break; + case 0x02: + ADCValue[1] = ( LPC_ADC->DR1 >> 6 ) & 0x3FF; + break; + case 0x04: + ADCValue[2] = ( LPC_ADC->DR2 >> 6 ) & 0x3FF; + break; + case 0x08: + ADCValue[3] = ( LPC_ADC->DR3 >> 6 ) & 0x3FF; + break; + case 0x10: + ADCValue[4] = ( LPC_ADC->DR4 >> 6 ) & 0x3FF; + break; + case 0x20: + ADCValue[5] = ( LPC_ADC->DR5 >> 6 ) & 0x3FF; + break; + case 0x40: + ADCValue[6] = ( LPC_ADC->DR6 >> 6 ) & 0x3FF; + break; + case 0x80: + ADCValue[7] = ( LPC_ADC->DR7 >> 6 ) & 0x3FF; + break; + default: + break; + } +#if BURST_MODE + channel_flag |= (regVal & 0xFF); + if ( (channel_flag & 0xFF) == 0xFF ) + { + /* All the bits in have been set, it indicates all the ADC + channels have been converted. */ + LPC_ADC->CR &= 0xF8FFFFFF; /* stop ADC now */ + ADCIntDone = 1; + } +#else + LPC_ADC->CR &= 0xF8FFFFFF; /* stop ADC now */ + ADCIntDone = 1; +#endif + } + return; +} +#endif + +/***************************************************************************** +** Function name: ADCInit +** +** Descriptions: initialize ADC channel +** +** parameters: ADC clock rate +** Returned value: None +** +*****************************************************************************/ +void ADCInit( uint32_t ADC_Clk ) +{ + uint32_t i; + + /* Disable Power down bit to the ADC block. */ + LPC_SYSCON->PDRUNCFG &= ~(0x1<<4); + + /* Enable AHB clock to the ADC. */ + LPC_SYSCON->SYSAHBCLKCTRL |= (1<<13); + + for ( i = 0; i < ADC_NUM; i++ ) + { + ADCValue[i] = 0x0; + } + /* Unlike some other pings, for ADC test, all the pins need + to set to analog mode. Bit 7 needs to be cleared according + to design team. */ + LPC_IOCON->PIO0_11 &= ~0x8F; /* ADC I/O config */ + LPC_IOCON->PIO0_11 |= 0x02; /* ADC IN0 */ + +#ifdef __JTAG_DISABLED + + LPC_IOCON->R_PIO1_0 &= ~0x8F; + LPC_IOCON->R_PIO1_0 |= 0x02; /* ADC IN1 */ + LPC_IOCON->R_PIO1_1 &= ~0x8F; + LPC_IOCON->R_PIO1_1 |= 0x02; /* ADC IN2 */ + LPC_IOCON->R_PIO1_2 &= ~0x8F; + LPC_IOCON->R_PIO1_2 |= 0x02; /* ADC IN3 */ +#ifdef __SWD_DISABLED + LPC_IOCON->SWDIO_PIO1_3 &= ~0x8F; + LPC_IOCON->SWDIO_PIO1_3 |= 0x02; /* ADC IN4 */ +#endif +#endif + LPC_IOCON->PIO1_4 &= ~0x8F; /* Clear bit7, change to analog mode. */ + LPC_IOCON->PIO1_4 |= 0x01; /* ADC IN5 */ + LPC_IOCON->PIO1_10 &= ~0x8F; /* Clear bit7, change to analog mode. */ + LPC_IOCON->PIO1_10 |= 0x01; /* ADC IN6 */ + LPC_IOCON->PIO1_11 &= ~0x8F; /* Clear bit7, change to analog mode. */ + LPC_IOCON->PIO1_11 |= 0x01; /* ADC IN7 */ + + LPC_ADC->CR = ( 0x01 << 0 ) | /* SEL=1,select channel 0~7 on ADC0 */ + (((SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/ADC_Clk-1)<<8) | /* CLKDIV = Fpclk / 1000000 - 1 */ + ( 0 << 16 ) | /* BURST = 0, no BURST, software controlled */ + ( 3 << 17 ) | /* CLKS = 0, 11 clocks/10 bits */ + ( 0 << 24 ) | /* START = 0 A/D conversion stops */ + ( 0 << 27 ); /* EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion) */ + + /* If POLLING, no need to do the following */ +#if ADC_INTERRUPT_FLAG + NVIC_EnableIRQ(ADC_IRQn); + LPC_ADC->INTEN = 0x1FF; /* Enable all interrupts */ +#endif + return; +} + +/***************************************************************************** +** Function name: ADCRead +** +** Descriptions: Read ADC channel +** +** parameters: Channel number +** Returned value: Value read, if interrupt driven, return channel # +** +*****************************************************************************/ +uint32_t ADCRead( uint8_t channelNum ) +{ +#if !ADC_INTERRUPT_FLAG + uint32_t regVal, ADC_Data; +#endif + + /* channel number is 0 through 7 */ + if ( channelNum >= ADC_NUM ) + { + channelNum = 0; /* reset channel number to 0 */ + } + LPC_ADC->CR &= 0xFFFFFF00; + LPC_ADC->CR |= (1 << 24) | (1 << channelNum); + /* switch channel,start A/D convert */ +#if !ADC_INTERRUPT_FLAG + while ( 1 ) /* wait until end of A/D convert */ + { + regVal = *(volatile unsigned long *)(LPC_ADC_BASE + + ADC_OFFSET + ADC_INDEX * channelNum); + /* read result of A/D conversion */ + if ( regVal & ADC_DONE ) + { + break; + } + } + + LPC_ADC->CR &= 0xF8FFFFFF; /* stop ADC now */ + if ( regVal & ADC_OVERRUN ) /* save data when it's not overrun, otherwise, return zero */ + { + return ( 0 ); + } + ADC_Data = ( regVal >> 6 ) & 0x3FF; + return ( ADC_Data ); /* return A/D conversion value */ +#else + return ( channelNum ); /* if it's interrupt driven, the ADC reading is + done inside the handler. so, return channel number */ +#endif +} + +/***************************************************************************** +** Function name: ADC0BurstRead +** +** Descriptions: Use burst mode to convert multiple channels once. +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void ADCBurstRead( void ) +{ + if ( LPC_ADC->CR & (0x7<<24) ) + { + LPC_ADC->CR &= ~(0x7<<24); + } + /* Test channel 5,6,7 using burst mode because they are not shared + with the JTAG pins. */ + LPC_ADC->CR &= ~0xFF; + /* Read all channels, 0 through 7. */ + LPC_ADC->CR |= (0xFF); + LPC_ADC->CR |= (0x1<<16); /* Set burst mode and start A/D convert */ + return; /* the ADC reading is done inside the + handler, return 0. */ +} + +/********************************************************************************* +** End Of File +*********************************************************************************/ diff --git a/firmware/src/adc.h b/firmware/src/adc.h new file mode 100644 index 0000000..d759d41 --- /dev/null +++ b/firmware/src/adc.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * $Id:: adc.h 3633 2010-06-01 23:03:16Z usb00423 $ + * Project: NXP LPC13xx ADC example + * + * Description: + * This file contains ADC 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 __ADC_H +#define __ADC_H + +#define ADC_INTERRUPT_FLAG 0 /* 1 is interrupt driven, 0 is polling */ +#define BURST_MODE 0 /* Burst mode works in interrupt driven mode only. */ +#define ADC_DEBUG 0 + +#define ADC_OFFSET 0x10 +#define ADC_INDEX 4 + +#define ADC_DONE 0x80000000 +#define ADC_OVERRUN 0x40000000 +#define ADC_ADINT 0x00010000 + +#define ADC_NUM 8 /* for LPC13xx */ +#define ADC_CLK 1000000 /* set to 1Mhz */ + +extern void ADC_IRQHandler( void ); +extern void ADCInit( uint32_t ADC_Clk ); +extern uint32_t ADCRead( uint8_t channelNum ); +extern void ADCBurstRead( void ); +#endif /* end __ADC_H */ +/***************************************************************************** +** End Of File +******************************************************************************/ diff --git a/firmware/src/edubrm.c b/firmware/src/edubrm.c index 585807f..b21e750 100644 --- a/firmware/src/edubrm.c +++ b/firmware/src/edubrm.c @@ -1,6 +1,7 @@ #include "config.h" #include "LPC13xx.h" #include "ssp.h" +#include "adc.h" #include "chars.h" #include "pbjt.h" @@ -56,3 +57,57 @@ void SetOutReport (uint8_t dst[], uint32_t length) } } } + +//static uint8_t x = 0; +void TIMER32_0_IRQHandler(void) { + LPC_TMR32B0->IR = 0xff; // clear interrupt + + /* + uint32_t x = LPC_TMR32B0->EMR & 1 ? 0xff : 0; + SSPSend((uint8_t*)&x, 1); + */ + + /* + uint32_t x = ADCRead(0); + uint8_t z = 0; + if (x >= 0) z = 0x01; + if (x >= 32) z = 0x02; + if (x >= 64) z = 0x04; + if (x >= 96) z = 0x08; + if (x >= 128) z = 0x10; + if (x >= 160) z = 0x20; + if (x >= 192) z = 0x40; + if (x >= 256) z = 0x80; + z |= 0x80; + SSPSend(&z, 1); + */ + + + // read PIO3_3 + uint8_t x = LPC_GPIO3->MASKED_ACCESS[1<<3]; + x = (x&(1<<3)) ? 0xff : 0; + SSPSend(&x, 1); + +} + +void PWMRun(void) { + + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9; // Enables clock for 32-bit counter/timer 0. + + LPC_IOCON->PIO1_6 &= ~0x07; + LPC_IOCON->PIO1_6 |= 0x02; // Selects function CT32B0_MAT0 + + LPC_TMR32B0->MR3 = 4294967; // period + LPC_TMR32B0->MR0 = 4294967/2; // duty + + LPC_TMR32B0->MCR = 1<<10; // Reset on MR3: the TC will be reset if MR3 matches it. + + LPC_TMR32B0->EMR = 3<<4; // Toggle the corresponding External Match bit/output. + + LPC_TMR32B0->PWMC = 1<<0 | 1<<3; // enable pwn + + LPC_TMR32B0->MCR |= 1<<9| 1<<0; NVIC_EnableIRQ(TIMER_32_0_IRQn); + + LPC_TMR32B0->TCR = 1; +} + diff --git a/firmware/src/edubrm.h b/firmware/src/edubrm.h index e844236..f9a84cb 100644 --- a/firmware/src/edubrm.h +++ b/firmware/src/edubrm.h @@ -1,2 +1,3 @@ void GetInReport (uint8_t src[], uint32_t length); void SetOutReport (uint8_t dst[], uint32_t length); +void PWMRun(void); diff --git a/firmware/src/gpio.h b/firmware/src/gpio.h index 46d467d..7d5032a 100644 --- a/firmware/src/gpio.h +++ b/firmware/src/gpio.h @@ -26,7 +26,7 @@ void GPIOIntDisable( uint32_t portNum, uint32_t bitPosi ); uint32_t GPIOIntStatus( uint32_t portNum, uint32_t bitPosi ); void GPIOIntClear( uint32_t portNum, uint32_t bitPosi ); -static LPC_GPIO_TypeDef (* const LPC_GPIO[4]) = { LPC_GPIO0, LPC_GPIO1, LPC_GPIO2, LPC_GPIO3 }; +//static LPC_GPIO_TypeDef (* const LPC_GPIO[4]) = { LPC_GPIO0, LPC_GPIO1, LPC_GPIO2, LPC_GPIO3 }; /***************************************************************************** ** Function name: GPIOSetValue @@ -38,11 +38,13 @@ static LPC_GPIO_TypeDef (* const LPC_GPIO[4]) = { LPC_GPIO0, LPC_GPIO1, LPC_GPIO ** Returned value: None ** *****************************************************************************/ +/* static __INLINE void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal ) { LPC_GPIO[portNum]->MASKED_ACCESS[(1<DIR &= ~(1<DIR |= 1 << 0; // SSP Enable with Master mode LPC_SSP->CR1 = (0x01<<1) | (0x00<<2); -NVIC_EnableIRQ(SSP_IRQn); +// NVIC_EnableIRQ(SSP_IRQn); /* Set SSPINMS registers to enable interrupts */ /* enable all error related interrupts */ diff --git a/firmware/src/usbhidrom_main.c b/firmware/src/usbhidrom_main.c index 2aa2e70..d633ecb 100644 --- a/firmware/src/usbhidrom_main.c +++ b/firmware/src/usbhidrom_main.c @@ -22,6 +22,7 @@ #include "rom_drivers.h" #include "config.h" #include "ssp.h" +#include "adc.h" #include "edubrm.h" #define EN_TIMER32_1 (1<<10) @@ -42,23 +43,12 @@ int main (void) SystemInit(); //#endif - LPC_IOCON->PIO1_6 &= ~0x07; - LPC_IOCON->PIO1_6 |= 0x02; // Selects function CT32B0_MAT0 + SSPInit(); - LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9; // Enables clock for 32-bit counter/timer 0. + ADCInit(ADC_CLK); - LPC_TMR32B0->MR3 = 4294967; // period - LPC_TMR32B0->MR0 = 4294967/2; // duty - - LPC_TMR32B0->MCR = 1<<10; // | 1<<9; // Reset on MR3: the TC will be reset if MR3 matches it. - - LPC_TMR32B0->EMR = 3<<4; // Toggle the corresponding External Match bit/output. - - LPC_TMR32B0->PWMC = 1<<0 | 1<<3; // enable pwn - - NVIC_EnableIRQ(TIMER_32_0_IRQn); - - LPC_TMR32B0->TCR = 1; + // enable read on pin PIO3_3 + LPC_GPIO3->DIR &= ~(1<<3); HidDevInfo.idVendor = USB_VENDOR_ID; HidDevInfo.idProduct = USB_PROD_ID; @@ -87,7 +77,7 @@ int main (void) for (n = 0; n < 75; n++) {} - SSPInit(); + PWMRun(); while (1) __WFI(); @@ -104,7 +94,7 @@ void USB_IRQHandler() void SSP_IRQHandler(void) { -// while(1) -// { -// } + while(1) + { + } }