diff options
Diffstat (limited to 'os')
27 files changed, 7468 insertions, 2 deletions
diff --git a/os/hal/platforms/LPC17xx/LPC17xx.h b/os/hal/platforms/LPC17xx/LPC17xx.h new file mode 100644 index 000000000..904d917cc --- /dev/null +++ b/os/hal/platforms/LPC17xx/LPC17xx.h @@ -0,0 +1,999 @@ +/****************************************************************************** + * @file: LPC17xx.h + * @purpose: CMSIS Cortex-M3 Core Peripheral Access Layer Header File for + * NXP LPC17xx Device Series + * @version: V1.10 + * @date: 24. September 2010 + *---------------------------------------------------------------------------- + * + * @note + * Copyright (C) 2010 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M3 + * processor based microcontrollers. This file can be freely distributed + * within development tools that are supporting such ARM based processors. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + + +#ifndef __LPC17xx_H__ +#define __LPC17xx_H__ + +/* + * ========================================================================== + * ---------- Interrupt Number Definition ----------------------------------- + * ========================================================================== + */ + +/** @addtogroup LPC17xx_System + * @{ + */ + +/** @brief IRQ interrupt source definition */ +typedef enum IRQn +{ +/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ + +/****** LPC17xx Specific Interrupt Numbers *******************************************************/ + WDT_IRQn = 0, /*!< Watchdog Timer Interrupt */ + TIMER0_IRQn = 1, /*!< Timer0 Interrupt */ + TIMER1_IRQn = 2, /*!< Timer1 Interrupt */ + TIMER2_IRQn = 3, /*!< Timer2 Interrupt */ + TIMER3_IRQn = 4, /*!< Timer3 Interrupt */ + UART0_IRQn = 5, /*!< UART0 Interrupt */ + UART1_IRQn = 6, /*!< UART1 Interrupt */ + UART2_IRQn = 7, /*!< UART2 Interrupt */ + UART3_IRQn = 8, /*!< UART3 Interrupt */ + PWM1_IRQn = 9, /*!< PWM1 Interrupt */ + I2C0_IRQn = 10, /*!< I2C0 Interrupt */ + I2C1_IRQn = 11, /*!< I2C1 Interrupt */ + I2C2_IRQn = 12, /*!< I2C2 Interrupt */ + SPI_IRQn = 13, /*!< SPI Interrupt */ + SSP0_IRQn = 14, /*!< SSP0 Interrupt */ + SSP1_IRQn = 15, /*!< SSP1 Interrupt */ + PLL0_IRQn = 16, /*!< PLL0 Lock (Main PLL) Interrupt */ + RTC_IRQn = 17, /*!< Real Time Clock Interrupt */ + EINT0_IRQn = 18, /*!< External Interrupt 0 Interrupt */ + EINT1_IRQn = 19, /*!< External Interrupt 1 Interrupt */ + EINT2_IRQn = 20, /*!< External Interrupt 2 Interrupt */ + EINT3_IRQn = 21, /*!< External Interrupt 3 Interrupt */ + ADC_IRQn = 22, /*!< A/D Converter Interrupt */ + BOD_IRQn = 23, /*!< Brown-Out Detect Interrupt */ + USB_IRQn = 24, /*!< USB Interrupt */ + CAN_IRQn = 25, /*!< CAN Interrupt */ + DMA_IRQn = 26, /*!< General Purpose DMA Interrupt */ + I2S_IRQn = 27, /*!< I2S Interrupt */ + ENET_IRQn = 28, /*!< Ethernet Interrupt */ + RIT_IRQn = 29, /*!< Repetitive Interrupt Timer Interrupt */ + MCPWM_IRQn = 30, /*!< Motor Control PWM Interrupt */ + QEI_IRQn = 31, /*!< Quadrature Encoder Interface Interrupt */ + PLL1_IRQn = 32, /*!< PLL1 Lock (USB PLL) Interrupt */ + USBActivity_IRQn = 33, /*!< USB Activity Interrupt(For wakeup only) */ + CANActivity_IRQn = 34 /*!< CAN Activity Interrupt(For wakeup only) */ +} IRQn_Type; + + +/* + * ========================================================================== + * ----------- Processor and Core Peripheral Section ------------------------ + * ========================================================================== + */ + +/* Configuration of the Cortex-M3 Processor and Core Peripherals */ +#define __MPU_PRESENT 1 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 5 /*!< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + + +#include "core_cm3.h" /* Cortex-M3 processor and core peripherals */ +#include "system_LPC17xx.h" /* System Header */ + + +/******************************************************************************/ +/* Device Specific Peripheral registers structures */ +/******************************************************************************/ + +#if defined ( __CC_ARM ) +#pragma anon_unions +#endif + +/*------------- System Control (SC) ------------------------------------------*/ +/** @brief System Control (SC) register structure definition */ +typedef struct +{ + __IO uint32_t FLASHCFG; /*!< Offset: 0x000 (R/W) Flash Accelerator Configuration Register */ + uint32_t RESERVED0[31]; + __IO uint32_t PLL0CON; /*!< Offset: 0x080 (R/W) PLL0 Control Register */ + __IO uint32_t PLL0CFG; /*!< Offset: 0x084 (R/W) PLL0 Configuration Register */ + __I uint32_t PLL0STAT; /*!< Offset: 0x088 (R/ ) PLL0 Status Register */ + __O uint32_t PLL0FEED; /*!< Offset: 0x08C ( /W) PLL0 Feed Register */ + uint32_t RESERVED1[4]; + __IO uint32_t PLL1CON; /*!< Offset: 0x0A0 (R/W) PLL1 Control Register */ + __IO uint32_t PLL1CFG; /*!< Offset: 0x0A4 (R/W) PLL1 Configuration Register */ + __I uint32_t PLL1STAT; /*!< Offset: 0x0A8 (R/ ) PLL1 Status Register */ + __O uint32_t PLL1FEED; /*!< Offset: 0x0AC ( /W) PLL1 Feed Register */ + uint32_t RESERVED2[4]; + __IO uint32_t PCON; /*!< Offset: 0x0C0 (R/W) Power Control Register */ + __IO uint32_t PCONP; /*!< Offset: 0x0C4 (R/W) Power Control for Peripherals Register */ + uint32_t RESERVED3[15]; + __IO uint32_t CCLKCFG; /*!< Offset: 0x104 (R/W) CPU Clock Configure Register */ + __IO uint32_t USBCLKCFG; /*!< Offset: 0x108 (R/W) USB Clock Configure Register */ + __IO uint32_t CLKSRCSEL; /*!< Offset: 0x10C (R/W) Clock Source Select Register */ + __IO uint32_t CANSLEEPCLR; /*!< Offset: 0x110 (R/W) CAN Sleep Clear Register */ + __IO uint32_t CANWAKEFLAGS; /*!< Offset: 0x114 (R/W) CAN Wake-up Flags Register */ + uint32_t RESERVED4[10]; + __IO uint32_t EXTINT; /*!< Offset: 0x140 (R/W) External Interrupt Flag Register */ + uint32_t RESERVED5[1]; + __IO uint32_t EXTMODE; /*!< Offset: 0x148 (R/W) External Interrupt Mode Register */ + __IO uint32_t EXTPOLAR; /*!< Offset: 0x14C (R/W) External Interrupt Polarity Register */ + uint32_t RESERVED6[12]; + __IO uint32_t RSID; /*!< Offset: 0x180 (R/W) Reset Source Identification Register */ + uint32_t RESERVED7[7]; + __IO uint32_t SCS; /*!< Offset: 0x1A0 (R/W) System Controls and Status Register */ + __IO uint32_t IRCTRIM; /* Clock Dividers */ + __IO uint32_t PCLKSEL0; /*!< Offset: 0x1A8 (R/W) Peripheral Clock Select 0 Register */ + __IO uint32_t PCLKSEL1; /*!< Offset: 0x1AC (R/W) Peripheral Clock Select 1 Register */ + uint32_t RESERVED8[4]; + __IO uint32_t USBIntSt; /*!< Offset: 0x1C0 (R/W) USB Interrupt Status Register */ + __IO uint32_t DMAREQSEL; /*!< Offset: 0x1C4 (R/W) DMA Request Select Register */ + __IO uint32_t CLKOUTCFG; /*!< Offset: 0x1C8 (R/W) Clock Output Configuration Register */ + + } LPC_SC_TypeDef; + +/*------------- Pin Connect Block (PINCON) -----------------------------------*/ +/** @brief Pin Connect Block (PINCON) register structure definition */ +typedef struct +{ + __IO uint32_t PINSEL0; /* !< Offset: 0x000 PIN Select0 (R/W) */ + __IO uint32_t PINSEL1; /* !< Offset: 0x004 PIN Select1 (R/W) */ + __IO uint32_t PINSEL2; /* !< Offset: 0x008 PIN Select2 (R/W) */ + __IO uint32_t PINSEL3; /* !< Offset: 0x00C PIN Select3 (R/W) */ + __IO uint32_t PINSEL4; /* !< Offset: 0x010 PIN Select4 (R/W) */ + __IO uint32_t PINSEL5; /* !< Offset: 0x014 PIN Select5 (R/W) */ + __IO uint32_t PINSEL6; /* !< Offset: 0x018 PIN Select6 (R/W) */ + __IO uint32_t PINSEL7; /* !< Offset: 0x01C PIN Select7 (R/W) */ + __IO uint32_t PINSEL8; /* !< Offset: 0x020 PIN Select8 (R/W) */ + __IO uint32_t PINSEL9; /* !< Offset: 0x024 PIN Select9 (R/W) */ + __IO uint32_t PINSEL10; /* !< Offset: 0x028 PIN Select20 (R/W) */ + uint32_t RESERVED0[5]; + __IO uint32_t PINMODE0; /* !< Offset: 0x040 PIN Mode0 (R/W) */ + __IO uint32_t PINMODE1; /* !< Offset: 0x044 PIN Mode1 (R/W) */ + __IO uint32_t PINMODE2; /* !< Offset: 0x048 PIN Mode2 (R/W) */ + __IO uint32_t PINMODE3; /* !< Offset: 0x04C PIN Mode3 (R/W) */ + __IO uint32_t PINMODE4; /* !< Offset: 0x050 PIN Mode4 (R/W) */ + __IO uint32_t PINMODE5; /* !< Offset: 0x054 PIN Mode5 (R/W) */ + __IO uint32_t PINMODE6; /* !< Offset: 0x058 PIN Mode6 (R/W) */ + __IO uint32_t PINMODE7; /* !< Offset: 0x05C PIN Mode7 (R/W) */ + __IO uint32_t PINMODE8; /* !< Offset: 0x060 PIN Mode8 (R/W) */ + __IO uint32_t PINMODE9; /* !< Offset: 0x064 PIN Mode9 (R/W) */ + __IO uint32_t PINMODE_OD0; /* !< Offset: 0x068 Open Drain PIN Mode0 (R/W) */ + __IO uint32_t PINMODE_OD1; /* !< Offset: 0x06C Open Drain PIN Mode1 (R/W) */ + __IO uint32_t PINMODE_OD2; /* !< Offset: 0x070 Open Drain PIN Mode2 (R/W) */ + __IO uint32_t PINMODE_OD3; /* !< Offset: 0x074 Open Drain PIN Mode3 (R/W) */ + __IO uint32_t PINMODE_OD4; /* !< Offset: 0x078 Open Drain PIN Mode4 (R/W) */ + __IO uint32_t I2CPADCFG; /* !< Offset: 0x07C I2C Pad Configure (R/W) */ +} LPC_PINCON_TypeDef; + +/*------------- General Purpose Input/Output (GPIO) --------------------------*/ +/** @brief General Purpose Input/Output (GPIO) register structure definition */ +typedef struct +{ + union { + __IO uint32_t FIODIR; /* !< Offset: 0x00 Port direction (R/W) */ + struct { + __IO uint16_t FIODIRL; + __IO uint16_t FIODIRH; + }; + struct { + __IO uint8_t FIODIR0; + __IO uint8_t FIODIR1; + __IO uint8_t FIODIR2; + __IO uint8_t FIODIR3; + }; + }; + uint32_t RESERVED0[3]; + union { + __IO uint32_t FIOMASK; /* !< Offset: 0x10 Port mask (R/W) */ + struct { + __IO uint16_t FIOMASKL; + __IO uint16_t FIOMASKH; + }; + struct { + __IO uint8_t FIOMASK0; + __IO uint8_t FIOMASK1; + __IO uint8_t FIOMASK2; + __IO uint8_t FIOMASK3; + }; + }; + union { + __IO uint32_t FIOPIN; /* !< Offset: 0x14 Port value (R/W) */ + struct { + __IO uint16_t FIOPINL; + __IO uint16_t FIOPINH; + }; + struct { + __IO uint8_t FIOPIN0; + __IO uint8_t FIOPIN1; + __IO uint8_t FIOPIN2; + __IO uint8_t FIOPIN3; + }; + }; + union { + __IO uint32_t FIOSET; /* !< Offset: 0x18 Port output set (R/W) */ + struct { + __IO uint16_t FIOSETL; + __IO uint16_t FIOSETH; + }; + struct { + __IO uint8_t FIOSET0; + __IO uint8_t FIOSET1; + __IO uint8_t FIOSET2; + __IO uint8_t FIOSET3; + }; + }; + union { + __O uint32_t FIOCLR; /* !< Offset: 0x1C Port output clear (R/W) */ + struct { + __O uint16_t FIOCLRL; + __O uint16_t FIOCLRH; + }; + struct { + __O uint8_t FIOCLR0; + __O uint8_t FIOCLR1; + __O uint8_t FIOCLR2; + __O uint8_t FIOCLR3; + }; + }; +} LPC_GPIO_TypeDef; + +/** @brief General Purpose Input/Output interrupt (GPIOINT) register structure definition */ +typedef struct +{ + __I uint32_t IntStatus; /*!< Offset: 0x000 (R/ ) GPIO overall Interrupt Status Register */ + __I uint32_t IO0IntStatR; /*!< Offset: 0x004 (R/ ) GPIO Interrupt Status Register 0 for Rising edge */ + __I uint32_t IO0IntStatF; /*!< Offset: 0x008 (R/ ) GPIO Interrupt Status Register 0 for Falling edge */ + __O uint32_t IO0IntClr; /*!< Offset: 0x00C (R/W) GPIO Interrupt Clear Register 0 */ + __IO uint32_t IO0IntEnR; /*!< Offset: 0x010 ( /W) GPIO Interrupt Enable Register 0 for Rising edge */ + __IO uint32_t IO0IntEnF; /*!< Offset: 0x014 (R/W) GPIO Interrupt Enable Register 0 for Falling edge */ + uint32_t RESERVED0[3]; + __I uint32_t IO2IntStatR; /*!< Offset: 0x000 (R/ ) GPIO Interrupt Status Register 2 for Rising edge */ + __I uint32_t IO2IntStatF; /*!< Offset: 0x000 (R/ ) GPIO Interrupt Status Register 2 for Falling edge */ + __O uint32_t IO2IntClr; /*!< Offset: 0x000 ( /W) GPIO Interrupt Clear Register 2 */ + __IO uint32_t IO2IntEnR; /*!< Offset: 0x000 (R/W) GPIO Interrupt Enable Register 2 for Rising edge */ + __IO uint32_t IO2IntEnF; /*!< Offset: 0x000 (R/W) GPIO Interrupt Enable Register 2 for Falling edge */ +} LPC_GPIOINT_TypeDef; + +/*------------- Timer (TIM) --------------------------------------------------*/ +/** @brief Timer (TIM) register structure definition */ +typedef struct +{ + __IO uint32_t IR; /*!< Offset: 0x000 (R/W) Interrupt Register */ + __IO uint32_t TCR; /*!< Offset: 0x004 (R/W) Timer Control Register */ + __IO uint32_t TC; /*!< Offset: 0x008 (R/W) Timer Counter Register */ + __IO uint32_t PR; /*!< Offset: 0x00C (R/W) Prescale Register */ + __IO uint32_t PC; /*!< Offset: 0x010 (R/W) Prescale Counter Register */ + __IO uint32_t MCR; /*!< Offset: 0x014 (R/W) Match Control Register */ + __IO uint32_t MR0; /*!< Offset: 0x018 (R/W) Match Register 0 */ + __IO uint32_t MR1; /*!< Offset: 0x01C (R/W) Match Register 1 */ + __IO uint32_t MR2; /*!< Offset: 0x020 (R/W) Match Register 2 */ + __IO uint32_t MR3; /*!< Offset: 0x024 (R/W) Match Register 3 */ + __IO uint32_t CCR; /*!< Offset: 0x028 (R/W) Capture Control Register */ + __I uint32_t CR0; /*!< Offset: 0x02C (R/ ) Capture Register 0 */ + __I uint32_t CR1; /*!< Offset: 0x030 (R/ ) Capture Register */ + uint32_t RESERVED0[2]; + __IO uint32_t EMR; /*!< Offset: 0x03C (R/W) External Match Register */ + uint32_t RESERVED1[12]; + __IO uint32_t CTCR; /*!< Offset: 0x070 (R/W) Count Control Register */ +} LPC_TIM_TypeDef; + +/*------------- Pulse-Width Modulation (PWM) ---------------------------------*/ +/** @brief Pulse-Width Modulation (PWM) register structure definition */ +typedef struct +{ + __IO uint32_t IR; /*!< Offset: 0x000 (R/W) Interrupt Register */ + __IO uint32_t TCR; /*!< Offset: 0x004 (R/W) Timer Control Register. Register */ + __IO uint32_t TC; /*!< Offset: 0x008 (R/W) Timer Counter Register */ + __IO uint32_t PR; /*!< Offset: 0x00C (R/W) Prescale Register */ + __IO uint32_t PC; /*!< Offset: 0x010 (R/W) Prescale Counter Register */ + __IO uint32_t MCR; /*!< Offset: 0x014 (R/W) Match Control Register */ + __IO uint32_t MR0; /*!< Offset: 0x018 (R/W) Match Register 0 */ + __IO uint32_t MR1; /*!< Offset: 0x01C (R/W) Match Register 1 */ + __IO uint32_t MR2; /*!< Offset: 0x020 (R/W) Match Register 2 */ + __IO uint32_t MR3; /*!< Offset: 0x024 (R/W) Match Register 3 */ + __IO uint32_t CCR; /*!< Offset: 0x028 (R/W) Capture Control Register */ + __I uint32_t CR0; /*!< Offset: 0x02C (R/ ) Capture Register 0 */ + __I uint32_t CR1; /*!< Offset: 0x030 (R/ ) Capture Register 1 */ + __I uint32_t CR2; /*!< Offset: 0x034 (R/ ) Capture Register 2 */ + __I uint32_t CR3; /*!< Offset: 0x038 (R/ ) Capture Register 3 */ + uint32_t RESERVED0; + __IO uint32_t MR4; /*!< Offset: 0x040 (R/W) Match Register 4 */ + __IO uint32_t MR5; /*!< Offset: 0x044 (R/W) Match Register 5 */ + __IO uint32_t MR6; /*!< Offset: 0x048 (R/W) Match Register 6 */ + __IO uint32_t PCR; /*!< Offset: 0x04C (R/W) PWM Control Register */ + __IO uint32_t LER; /*!< Offset: 0x050 (R/W) Load Enable Register */ + uint32_t RESERVED1[7]; + __IO uint32_t CTCR; /*!< Offset: 0x070 (R/W) Count Control Register */ +} LPC_PWM_TypeDef; + +/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/ +/** @brief Universal Asynchronous Receiver Transmitter (UART) register structure definition */ +typedef struct +{ + union { + __I uint32_t RBR; /*!< Offset: 0x000 Receiver Buffer Register (R/ ) */ + __O uint32_t THR; /*!< Offset: 0x000 Transmit Holding Register ( /W) */ + __IO uint32_t DLL; /*!< Offset: 0x000 Divisor Latch LSB (R/W) */ + }; + union { + __IO uint32_t DLM; /*!< Offset: 0x004 Divisor Latch MSB (R/W) */ + __IO uint32_t IER; /*!< Offset: 0x004 Interrupt Enable Register (R/W) */ + }; + union { + __I uint32_t IIR; /*!< Offset: 0x008 Interrupt ID Register (R/ ) */ + __O uint32_t FCR; /*!< Offset: 0x008 FIFO Control Register ( /W) */ + }; + __IO uint32_t LCR; /*!< Offset: 0x00C Line Control Register (R/W) */ + uint32_t RESERVED0; + __I uint32_t LSR; /*!< Offset: 0x014 Line Status Register (R/ ) */ + uint32_t RESERVED1; + __IO uint32_t SCR; /*!< Offset: 0x01C Scratch Pad Register (R/W) */ + __IO uint32_t ACR; /*!< Offset: 0x020 Auto-baud Control Register (R/W) */ + __IO uint32_t ICR; /*!< Offset: 0x024 IrDA Control Register (R/W) */ + __IO uint32_t FDR; /*!< Offset: 0x028 Fractional Divider Register (R/W) */ + uint32_t RESERVED2; + __IO uint32_t TER; /*!< Offset: 0x030 Transmit Enable Register (R/W) */ +} LPC_UART_TypeDef; + +/** @brief Universal Asynchronous Receiver Transmitter 0 (UART0) register structure definition */ +typedef struct +{ + union { + __I uint32_t RBR; /*!< Offset: 0x000 Receiver Buffer Register (R/ ) */ + __O uint32_t THR; /*!< Offset: 0x000 Transmit Holding Register ( /W) */ + __IO uint32_t DLL; /*!< Offset: 0x000 Divisor Latch LSB (R/W) */ + }; + union { + __IO uint32_t DLM; /*!< Offset: 0x004 Divisor Latch MSB (R/W) */ + __IO uint32_t IER; /*!< Offset: 0x000 Interrupt Enable Register (R/W) */ + }; + union { + __I uint32_t IIR; /*!< Offset: 0x008 Interrupt ID Register (R/ ) */ + __O uint32_t FCR; /*!< Offset: 0x008 FIFO Control Register ( /W) */ + }; + __IO uint32_t LCR; /*!< Offset: 0x00C Line Control Register (R/W) */ + __IO uint32_t MCR; /*!< Offset: 0x010 Modem control Register (R/W) */ + __I uint32_t LSR; /*!< Offset: 0x014 Line Status Register (R/ ) */ + __I uint32_t MSR; /*!< Offset: 0x018 Modem status Register (R/ ) */ + __IO uint32_t SCR; /*!< Offset: 0x01C Scratch Pad Register (R/W) */ + __IO uint32_t ACR; /*!< Offset: 0x020 Auto-baud Control Register (R/W) */ + uint32_t RESERVED0; + __IO uint32_t FDR; /*!< Offset: 0x028 Fractional Divider Register (R/W) */ + uint32_t RESERVED1; + __IO uint32_t TER; /*!< Offset: 0x030 Transmit Enable Register (R/W) */ + uint32_t RESERVED2[6]; + __IO uint32_t RS485CTRL; /*!< Offset: 0x04C RS-485/EIA-485 Control Register (R/W) */ + __IO uint32_t ADRMATCH; /*!< Offset: 0x050 RS-485/EIA-485 address match Register (R/W) */ + __IO uint32_t RS485DLY; /*!< Offset: 0x054 RS-485/EIA-485 direction control delay Register (R/W) */ +} LPC_UART1_TypeDef; + +/*------------- Serial Peripheral Interface (SPI) ----------------------------*/ +/** @brief Serial Peripheral Interface (SPI) register structure definition */ +typedef struct +{ + __IO uint32_t SPCR; /*!< Offset: 0x000 SPI Control Register (R/W) */ + __I uint32_t SPSR; /*!< Offset: 0x004 SPI Status Register (R/) */ + __IO uint32_t SPDR; /*!< Offset: 0x008 SPI Data Register (R/W) */ + __IO uint32_t SPCCR; /*!< Offset: 0x00C SPI Clock Counter Register (R/W) */ + uint32_t RESERVED0[3]; + __IO uint32_t SPINT; /*!< Offset: 0x01C SPI Interrupt Flag Register (R/W) */ +} LPC_SPI_TypeDef; + +/*------------- Synchronous Serial Communication (SSP) -----------------------*/ +/** @brief Synchronous Serial Communication (SSP) register structure definition */ +typedef struct +{ + __IO uint32_t CR0; /*!< Offset: 0x000 (R/W) Control Register 0 */ + __IO uint32_t CR1; /*!< Offset: 0x004 (R/W) Control Register 1 */ + __IO uint32_t DR; /*!< Offset: 0x008 (R/W) Data Register */ + __I uint32_t SR; /*!< Offset: 0x00C (R/ ) Status Register */ + __IO uint32_t CPSR; /*!< Offset: 0x010 (R/W) Clock Prescale Register */ + __IO uint32_t IMSC; /*!< Offset: 0x014 (R/W) Interrupt Mask Set and Clear Register */ + __IO uint32_t RIS; /*!< Offset: 0x018 (R/W) Raw Interrupt Status Register */ + __IO uint32_t MIS; /*!< Offset: 0x01C (R/W) Masked Interrupt Status Register */ + __IO uint32_t ICR; /*!< Offset: 0x020 (R/W) SSPICR Interrupt Clear Register */ + __IO uint32_t DMACR; /*!< Offset: 0x024 (R/W) DMA Control Register */ +} LPC_SSP_TypeDef; + +/*------------- Inter-Integrated Circuit (I2C) -------------------------------*/ +/** @brief Inter-Integrated Circuit (I2C) register structure definition */ +typedef struct +{ + __IO uint32_t CONSET; /*!< Offset: 0x000 (R/W) I2C Control Set Register */ + __I uint32_t STAT; /*!< Offset: 0x004 (R/ ) I2C Status Register */ + __IO uint32_t DAT; /*!< Offset: 0x008 (R/W) I2C Data Register */ + __IO uint32_t ADR0; /*!< Offset: 0x00C (R/W) I2C Slave Address Register 0 */ + __IO uint32_t SCLH; /*!< Offset: 0x010 (R/W) SCH Duty Cycle Register High Half Word */ + __IO uint32_t SCLL; /*!< Offset: 0x014 (R/W) SCL Duty Cycle Register Low Half Word */ + __O uint32_t CONCLR; /*!< Offset: 0x018 (R/W) I2C Control Clear Register */ + __IO uint32_t MMCTRL; /*!< Offset: 0x01C (R/W) Monitor mode control register */ + __IO uint32_t ADR1; /*!< Offset: 0x020 (R/W) I2C Slave Address Register 1 */ + __IO uint32_t ADR2; /*!< Offset: 0x024 (R/W) I2C Slave Address Register 2 */ + __IO uint32_t ADR3; /*!< Offset: 0x028 (R/W) I2C Slave Address Register 3 */ + __I uint32_t DATA_BUFFER; /*!< Offset: 0x02C (R/ ) Data buffer Register */ + __IO uint32_t MASK0; /*!< Offset: 0x030 (R/W) I2C Slave address mask register 0 */ + __IO uint32_t MASK1; /*!< Offset: 0x034 (R/W) I2C Slave address mask register 1 */ + __IO uint32_t MASK2; /*!< Offset: 0x038 (R/W) I2C Slave address mask register 2 */ + __IO uint32_t MASK3; /*!< Offset: 0x03C (R/W) I2C Slave address mask register 3 */ +} LPC_I2C_TypeDef; + +/*------------- Inter IC Sound (I2S) -----------------------------------------*/ +/** @brief Inter IC Sound (I2S) register structure definition */ +typedef struct +{ + __IO uint32_t DAO; /*!< Offset: 0x000 (R/W) Digital Audio Output Register */ + __IO uint32_t DAI; /*!< Offset: 0x004 (R/W) Digital Audio Input Register */ + __O uint32_t TXFIFO; /*!< Offset: 0x008 ( /W) Transmit FIFO */ + __I uint32_t RXFIFO; /*!< Offset: 0x00C (R/ ) Receive FIFO */ + __I uint32_t STATE; /*!< Offset: 0x010 (R/W) Status Feedback Register */ + __IO uint32_t DMA1; /*!< Offset: 0x014 (R/W) DMA Configuration Register 1 */ + __IO uint32_t DMA2; /*!< Offset: 0x018 (R/W) DMA Configuration Register 2 */ + __IO uint32_t IRQ; /*!< Offset: 0x01C (R/W) Interrupt Request Control Register */ + __IO uint32_t TXRATE; /*!< Offset: 0x020 (R/W) Transmit reference clock divider Register */ + __IO uint32_t RXRATE; /*!< Offset: 0x024 (R/W) Receive reference clock divider Register */ + __IO uint32_t TXBITRATE; /*!< Offset: 0x028 (R/W) Transmit bit rate divider Register */ + __IO uint32_t RXBITRATE; /*!< Offset: 0x02C (R/W) Receive bit rate divider Register */ + __IO uint32_t TXMODE; /*!< Offset: 0x030 (R/W) Transmit mode control Register */ + __IO uint32_t RXMODE; /*!< Offset: 0x034 (R/W) Receive mode control Register */ +} LPC_I2S_TypeDef; + +/*------------- Repetitive Interrupt Timer (RIT) -----------------------------*/ +/** @brief Repetitive Interrupt Timer (RIT) register structure definition */ +typedef struct +{ + __IO uint32_t RICOMPVAL; + __IO uint32_t RIMASK; + __IO uint32_t RICTRL; + __IO uint32_t RICOUNTER; +} LPC_RIT_TypeDef; + +/*------------- Real-Time Clock (RTC) ----------------------------------------*/ +/** @brief Real-Time Clock (RTC) register structure definition */ +typedef struct +{ + __IO uint32_t ILR; /*!< Offset: 0x000 (R/W) Interrupt Location Register */ + uint32_t RESERVED0; + __IO uint32_t CCR; /*!< Offset: 0x008 (R/W) Clock Control Register */ + __IO uint32_t CIIR; /*!< Offset: 0x00C (R/W) Counter Increment Interrupt Register */ + __IO uint32_t AMR; /*!< Offset: 0x010 (R/W) Alarm Mask Register */ + __I uint32_t CTIME0; /*!< Offset: 0x014 (R/ ) Consolidated Time Register 0 */ + __I uint32_t CTIME1; /*!< Offset: 0x018 (R/ ) Consolidated Time Register 1 */ + __I uint32_t CTIME2; /*!< Offset: 0x01C (R/ ) Consolidated Time Register 2 */ + __IO uint32_t SEC; /*!< Offset: 0x020 (R/W) Seconds Counter Register */ + __IO uint32_t MIN; /*!< Offset: 0x024 (R/W) Minutes Register */ + __IO uint32_t HOUR; /*!< Offset: 0x028 (R/W) Hours Register */ + __IO uint32_t DOM; /*!< Offset: 0x02C (R/W) Day of Month Register */ + __IO uint32_t DOW; /*!< Offset: 0x030 (R/W) Day of Week Register */ + __IO uint32_t DOY; /*!< Offset: 0x034 (R/W) Day of Year Register */ + __IO uint32_t MONTH; /*!< Offset: 0x038 (R/W) Months Register */ + __IO uint32_t YEAR; /*!< Offset: 0x03C (R/W) Years Register */ + __IO uint32_t CALIBRATION; /*!< Offset: 0x040 (R/W) Calibration Value Register */ + __IO uint32_t GPREG0; /*!< Offset: 0x044 (R/W) General Purpose Register 0 */ + __IO uint32_t GPREG1; /*!< Offset: 0x048 (R/W) General Purpose Register 1 */ + __IO uint32_t GPREG2; /*!< Offset: 0x04C (R/W) General Purpose Register 2 */ + __IO uint32_t GPREG3; /*!< Offset: 0x050 (R/W) General Purpose Register 3 */ + __IO uint32_t GPREG4; /*!< Offset: 0x054 (R/W) General Purpose Register 4 */ + __IO uint32_t RTC_AUXEN; /*!< Offset: 0x058 (R/W) RTC Auxiliary Enable Register */ + __IO uint32_t RTC_AUX; /*!< Offset: 0x05C (R/W) RTC Auxiliary Control Register */ + __IO uint32_t ALSEC; /*!< Offset: 0x060 (R/W) Alarm value for Seconds */ + __IO uint32_t ALMIN; /*!< Offset: 0x064 (R/W) Alarm value for Minutes */ + __IO uint32_t ALHOUR; /*!< Offset: 0x068 (R/W) Alarm value for Hours */ + __IO uint32_t ALDOM; /*!< Offset: 0x06C (R/W) Alarm value for Day of Month */ + __IO uint32_t ALDOW; /*!< Offset: 0x070 (R/W) Alarm value for Day of Week */ + __IO uint32_t ALDOY; /*!< Offset: 0x074 (R/W) Alarm value for Day of Year */ + __IO uint32_t ALMON; /*!< Offset: 0x078 (R/W) Alarm value for Months */ + __IO uint32_t ALYEAR; /*!< Offset: 0x07C (R/W) Alarm value for Year */ +} LPC_RTC_TypeDef; + +/*------------- Watchdog Timer (WDT) -----------------------------------------*/ +/** @brief Watchdog Timer (WDT) register structure definition */ +typedef struct +{ + __IO uint32_t MOD; /*!< Offset: 0x000 (R/W) Watchdog mode Register */ + __IO uint32_t TC; /*!< Offset: 0x004 (R/W) Watchdog timer constant Register */ + __O uint32_t FEED; /*!< Offset: 0x008 ( /W) Watchdog feed sequence Register */ + __I uint32_t TV; /*!< Offset: 0x00C (R/ ) Watchdog timer value Register */ + __IO uint32_t WDCLKSEL; +} LPC_WDT_TypeDef; + +/*------------- Analog-to-Digital Converter (ADC) ----------------------------*/ +/** @brief Analog-to-Digital Converter (ADC) register structure definition */ +typedef struct +{ + __IO uint32_t CR; /*!< Offset: 0x000 (R/W) A/D Control Register */ + __IO uint32_t GDR; /*!< Offset: 0x004 (R/W) A/D Global Data Register */ + uint32_t RESERVED0; + __IO uint32_t INTEN; /*!< Offset: 0x00C (R/W) A/D Interrupt Enable Register */ + __I uint32_t DR[8]; /*!< Offset: 0x010 (R/ ) A/D Channel # Data Register */ + __I uint32_t STAT; /*!< Offset: 0x030 (R/ ) A/D Status Register */ + __IO uint32_t ADTRM; /*!< Offset: 0x034 (R/W) ADC trim Register */ +} LPC_ADC_TypeDef; + +/*------------- Digital-to-Analog Converter (DAC) ----------------------------*/ +/** @brief Digital-to-Analog Converter (DAC) register structure definition */ +typedef struct +{ + __IO uint32_t CR; /*!< Offset: 0x000 (R/W) D/A Converter Register */ + __IO uint32_t CTRL; /*!< Offset: 0x004 (R/W) DAC Control register */ + __IO uint32_t CNTVAL; /*!< Offset: 0x008 (R/W) DAC Counter Value Register */ +} LPC_DAC_TypeDef; + +/*------------- Motor Control Pulse-Width Modulation (MCPWM) -----------------*/ +/** @brief Motor Control Pulse-Width Modulation (MCPWM) register structure definition */ +typedef struct +{ + __I uint32_t CON; /*!< Offset: 0x000 (R/ ) PWM Control read address Register */ + __O uint32_t CON_SET; /*!< Offset: 0x004 ( /W) PWM Control set address Register */ + __O uint32_t CON_CLR; /*!< Offset: 0x008 ( /W) PWM Control clear address Register */ + __I uint32_t CAPCON; /*!< Offset: 0x00C (R/ ) Capture Control read address Register */ + __O uint32_t CAPCON_SET; /*!< Offset: 0x010 ( /W) Capture Control set address Register */ + __O uint32_t CAPCON_CLR; /*!< Offset: 0x014 ( /W) Event Control clear address Register */ + __IO uint32_t TC0; /*!< Offset: 0x018 (R/W) Timer Counter Register, channel 0 */ + __IO uint32_t TC1; /*!< Offset: 0x01C (R/W) Timer Counter Register, channel 1 */ + __IO uint32_t TC2; /*!< Offset: 0x020 (R/W) Timer Counter Register, channel 2 */ + __IO uint32_t LIM0; /*!< Offset: 0x024 (R/W) Limit Register, channel 0 */ + __IO uint32_t LIM1; /*!< Offset: 0x028 (R/W) Limit Register, channel 1 */ + __IO uint32_t LIM2; /*!< Offset: 0x02C (R/W) Limit Register, channel 2 */ + __IO uint32_t MAT0; /*!< Offset: 0x030 (R/W) Match Register, channel 0 */ + __IO uint32_t MAT1; /*!< Offset: 0x034 (R/W) Match Register, channel 1 */ + __IO uint32_t MAT2; /*!< Offset: 0x038 (R/W) Match Register, channel 2 */ + __IO uint32_t DT; /*!< Offset: 0x03C (R/W) Dead time Register */ + __IO uint32_t CP; /*!< Offset: 0x040 (R/W) Commutation Pattern Register */ + __IO uint32_t CAP0; /*!< Offset: 0x044 (R/W) Capture Register, channel 0 */ + __IO uint32_t CAP1; /*!< Offset: 0x048 (R/W) Capture Register, channel 1 */ + __IO uint32_t CAP2; /*!< Offset: 0x04C (R/W) Capture Register, channel 2 */ + __I uint32_t INTEN; /*!< Offset: 0x050 (R/ ) Interrupt Enable read Register */ + __O uint32_t INTEN_SET; /*!< Offset: 0x054 ( /W) Interrupt Enable set address Register */ + __O uint32_t INTEN_CLR; /*!< Offset: 0x058 ( /W) Interrupt Enable clear address Register */ + __I uint32_t CNTCON; /*!< Offset: 0x05C (R/ ) Count Control read address Register */ + __O uint32_t CNTCON_SET; /*!< Offset: 0x060 ( /W) Count Control set address Register */ + __O uint32_t CNTCON_CLR; /*!< Offset: 0x064 ( /W) Count Control clear address Register */ + __I uint32_t INTF; /*!< Offset: 0x068 (R/ ) Interrupt flags read address Register */ + __O uint32_t INTF_SET; /*!< Offset: 0x06C ( /W) Interrupt flags set address Register */ + __O uint32_t INTF_CLR; /*!< Offset: 0x070 ( /W) Interrupt flags clear address Register */ + __O uint32_t CAP_CLR; /*!< Offset: 0x074 ( /W) Capture clear address Register */ +} LPC_MCPWM_TypeDef; + +/*------------- Quadrature Encoder Interface (QEI) ---------------------------*/ +/** @brief Quadrature Encoder Interface (QEI) register structure definition */ +typedef struct +{ + __O uint32_t CON; /*!< Offset: 0x000 ( /W) Control Register */ + __I uint32_t STAT; /*!< Offset: 0x004 (R/ ) Encoder Status Register */ + __IO uint32_t CONF; /*!< Offset: 0x008 (R/W) Configuration Register */ + __I uint32_t POS; /*!< Offset: 0x00C (R/ ) Position Register */ + __IO uint32_t MAXPOS; /*!< Offset: 0x010 (R/W) Maximum position Register */ + __IO uint32_t CMPOS0; /*!< Offset: 0x014 (R/W) Position compare Register 0 */ + __IO uint32_t CMPOS1; /*!< Offset: 0x018 (R/W) Position compare Register 1 */ + __IO uint32_t CMPOS2; /*!< Offset: 0x01C (R/W) Position compare Register 2 */ + __I uint32_t INXCNT; /*!< Offset: 0x020 (R/ ) Index count Register */ + __IO uint32_t INXCMP0; /*!< Offset: 0x024 (R/W) Index compare Register 0 */ + __IO uint32_t LOAD; /*!< Offset: 0x028 (R/W) Velocity timer reload Register */ + __I uint32_t TIME; /*!< Offset: 0x02C (R/ ) Velocity timer Register */ + __I uint32_t VEL; /*!< Offset: 0x030 (R/ ) Velocity counter Register */ + __I uint32_t CAP; /*!< Offset: 0x034 (R/ ) Velocity capture Register */ + __IO uint32_t VELCOMP; /*!< Offset: 0x038 (R/W) Velocity compare Register */ + __IO uint32_t FILTER; + uint32_t RESERVED0[998]; + __O uint32_t IEC; /*!< Offset: 0xFD8 ( /W) Interrupt enable clear Register */ + __O uint32_t IES; /*!< Offset: 0xFDC ( /W) Interrupt enable set Register */ + __I uint32_t INTSTAT; /*!< Offset: 0xFE0 (R/ ) Interrupt status Register */ + __I uint32_t IE; /*!< Offset: 0xFE4 (R/ ) Interrupt enable Register */ + __O uint32_t CLR; /*!< Offset: 0xFE8 ( /W) Interrupt status clear Register */ + __O uint32_t SET; /*!< Offset: 0xFEC ( /W) Interrupt status set Register */ +} LPC_QEI_TypeDef; + +/*------------- Controller Area Network (CAN) --------------------------------*/ +/** @brief Controller Area Network Acceptance Filter RAM (CANAF_RAM)structure definition */ +typedef struct +{ + __IO uint32_t mask[512]; /*!< Offset: 0x000 (R/W) Acceptance Filter RAM */ +} LPC_CANAF_RAM_TypeDef; + +/** @brief Controller Area Network Acceptance Filter(CANAF) register structure definition */ +typedef struct /* Acceptance Filter Registers */ +{ + __IO uint32_t AFMR; /*!< Offset: 0x000 (R/W) Acceptance Filter Register */ + __IO uint32_t SFF_sa; /*!< Offset: 0x004 (R/W) Standard Frame Individual Start Address Register */ + __IO uint32_t SFF_GRP_sa; /*!< Offset: 0x008 (R/W) Standard Frame Group Start Address Register */ + __IO uint32_t EFF_sa; /*!< Offset: 0x00C (R/W) Extended Frame Start Address Register */ + __IO uint32_t EFF_GRP_sa; /*!< Offset: 0x010 (R/W) Extended Frame Group Start Address Register */ + __IO uint32_t ENDofTable; /*!< Offset: 0x014 (R/W) End of AF Tables Register */ + __I uint32_t LUTerrAd; /*!< Offset: 0x018 (R/ ) LUT Error Address Register */ + __I uint32_t LUTerr; /*!< Offset: 0x01C (R/ ) LUT Error Register */ + __IO uint32_t FCANIE; /*!< Offset: 0x020 (R/W) Global FullCANInterrupt Enable Register */ + __IO uint32_t FCANIC0; /*!< Offset: 0x024 (R/W) FullCAN Interrupt and Capture Register 0 */ + __IO uint32_t FCANIC1; /*!< Offset: 0x028 (R/W) FullCAN Interrupt and Capture Register 1 */ +} LPC_CANAF_TypeDef; + +/** @brief Controller Area Network Central (CANCR) register structure definition */ +typedef struct /* Central Registers */ +{ + __I uint32_t TxSR; /*!< Offset: 0x000 (R/ ) CAN Central Transmit Status Register */ + __I uint32_t RxSR; /*!< Offset: 0x004 (R/ ) CAN Central Receive Status Register */ + __I uint32_t MSR; /*!< Offset: 0x008 (R/ ) CAN Central Miscellaneous Register */ +} LPC_CANCR_TypeDef; + +/** @brief Controller Area Network Controller (CAN) register structure definition */ +typedef struct /* Controller Registers */ +{ + __IO uint32_t MOD; /*!< Offset: 0x000 (R/W) CAN Mode Register */ + __O uint32_t CMR; /*!< Offset: 0x004 ( /W) CAN Command Register */ + __IO uint32_t GSR; /*!< Offset: 0x008 (R/W) CAN Global Status Register */ + __I uint32_t ICR; /*!< Offset: 0x00C (R/ ) CAN Interrupt and Capture Register */ + __IO uint32_t IER; /*!< Offset: 0x010 (R/W) CAN Interrupt Enable Register */ + __IO uint32_t BTR; /*!< Offset: 0x014 (R/W) CAN Bus Timing Register */ + __IO uint32_t EWL; /*!< Offset: 0x018 (R/W) CAN Error Warning Limit Register */ + __I uint32_t SR; /*!< Offset: 0x01C (R/ ) CAN Status Register */ + __IO uint32_t RFS; /*!< Offset: 0x020 (R/W) CAN Receive Frame Status Register */ + __IO uint32_t RID; /*!< Offset: 0x024 (R/W) CAN Receive Identifier Register */ + __IO uint32_t RDA; /*!< Offset: 0x028 (R/W) CAN Receive Data Register A */ + __IO uint32_t RDB; /*!< Offset: 0x02C (R/W) CAN Receive Data Register B */ + __IO uint32_t TFI1; /*!< Offset: 0x030 (R/W) CAN Transmit Frame Information Register 1 */ + __IO uint32_t TID1; /*!< Offset: 0x034 (R/W) CAN Transmit Identifier Register 1 */ + __IO uint32_t TDA1; /*!< Offset: 0x038 (R/W) CAN Transmit Data Register A 1 */ + __IO uint32_t TDB1; /*!< Offset: 0x03C (R/W) CAN Transmit Data Register B 1 */ + __IO uint32_t TFI2; /*!< Offset: 0x040 (R/W) CAN Transmit Frame Information Register 2 */ + __IO uint32_t TID2; /*!< Offset: 0x044 (R/W) CAN Transmit Identifier Register 2 */ + __IO uint32_t TDA2; /*!< Offset: 0x048 (R/W) CAN Transmit Data Register A 2 */ + __IO uint32_t TDB2; /*!< Offset: 0x04C (R/W) CAN Transmit Data Register B 2 */ + __IO uint32_t TFI3; /*!< Offset: 0x050 (R/W) CAN Transmit Frame Information Register 3 */ + __IO uint32_t TID3; /*!< Offset: 0x054 (R/W) CAN Transmit Identifier Register 3 */ + __IO uint32_t TDA3; /*!< Offset: 0x058 (R/W) CAN Transmit Data Register A 3 */ + __IO uint32_t TDB3; /*!< Offset: 0x05C (R/W) CAN Transmit Data Register B 3 */ +} LPC_CAN_TypeDef; + +/*------------- General Purpose Direct Memory Access (GPDMA) -----------------*/ +/** @brief General Purpose Direct Memory Access (GPDMA) register structure definition */ +typedef struct /* Common Registers */ +{ + __I uint32_t IntStat; /*!< Offset: 0x000 (R/ ) DMA Interrupt Status Register */ + __I uint32_t IntTCStat; /*!< Offset: 0x004 (R/ ) DMA Interrupt Terminal Count Request Status Register */ + __O uint32_t IntTCClear; /*!< Offset: 0x008 ( /W) DMA Interrupt Terminal Count Request Clear Register */ + __I uint32_t IntErrStat; /*!< Offset: 0x00C (R/ ) DMA Interrupt Error Status Register */ + __O uint32_t IntErrClr; /*!< Offset: 0x010 ( /W) DMA Interrupt Error Clear Register */ + __I uint32_t RawIntTCStat; /*!< Offset: 0x014 (R/ ) DMA Raw Interrupt Terminal Count Status Register */ + __I uint32_t RawIntErrStat; /*!< Offset: 0x018 (R/ ) DMA Raw Error Interrupt Status Register */ + __I uint32_t EnbldChns; /*!< Offset: 0x01C (R/ ) DMA Enabled Channel Register */ + __IO uint32_t SoftBReq; /*!< Offset: 0x020 (R/W) DMA Software Burst Request Register */ + __IO uint32_t SoftSReq; /*!< Offset: 0x024 (R/W) DMA Software Single Request Register */ + __IO uint32_t SoftLBReq; /*!< Offset: 0x028 (R/W) DMA Software Last Burst Request Register */ + __IO uint32_t SoftLSReq; /*!< Offset: 0x02C (R/W) DMA Software Last Single Request Register */ + __IO uint32_t Config; /*!< Offset: 0x030 (R/W) DMA Configuration Register */ + __IO uint32_t Sync; /*!< Offset: 0x034 (R/W) DMA Synchronization Register */ +} LPC_GPDMA_TypeDef; + +/** @brief General Purpose Direct Memory Access Channel (GPDMACH) register structure definition */ +typedef struct /* Channel Registers */ +{ + __IO uint32_t CSrcAddr; /*!< Offset: 0x000 (R/W) DMA Channel # Source Address Register */ + __IO uint32_t CDestAddr; /*!< Offset: 0x004 (R/W) DMA Channel # Destination Address Register */ + __IO uint32_t CLLI; /*!< Offset: 0x008 (R/W) DMA Channel # Linked List Item Register */ + __IO uint32_t CControl; /*!< Offset: 0x00C (R/W) DMA Channel # Control Register */ + __IO uint32_t CConfig; /*!< Offset: 0x010 (R/W) DMA Channel # Configuration Register */ +} LPC_GPDMACH_TypeDef; + +/*------------- Universal Serial Bus (USB) -----------------------------------*/ +/** @brief Universal Serial Bus (USB) register structure definition */ +typedef struct +{ + __I uint32_t Revision; /*!< Offset: 0x000 (R/ ) Revision Register */ + __IO uint32_t Control; /*!< Offset: 0x004 (R/W) Control Register */ + __IO uint32_t CommandStatus; /*!< Offset: 0x008 (R/W) Command / Status Register */ + __IO uint32_t InterruptStatus; /*!< Offset: 0x00C (R/W) Interrupt Status Register */ + __IO uint32_t InterruptEnable; /*!< Offset: 0x010 (R/W) Interrupt Enable Register */ + __IO uint32_t InterruptDisable; /*!< Offset: 0x014 (R/W) Interrupt Disable Register */ + __IO uint32_t HCCA; /*!< Offset: 0x018 (R/W) Host Controller communication Area Register */ + __I uint32_t PeriodCurrentED; /*!< Offset: 0x01C (R/ ) Register */ + __IO uint32_t ControlHeadED; /*!< Offset: 0x020 (R/W) Register */ + __IO uint32_t ControlCurrentED; /*!< Offset: 0x024 (R/W) Register */ + __IO uint32_t BulkHeadED; /*!< Offset: 0x028 (R/W) Register */ + __IO uint32_t BulkCurrentED; /*!< Offset: 0x02C (R/W) Register */ + __I uint32_t DoneHead; /*!< Offset: 0x030 (R/ ) Register */ + __IO uint32_t FmInterval; /*!< Offset: 0x034 (R/W) Register */ + __I uint32_t FmRemaining; /*!< Offset: 0x038 (R/ ) Register */ + __I uint32_t FmNumber; /*!< Offset: 0x03C (R/ ) Register */ + __IO uint32_t PeriodicStart; /*!< Offset: 0x040 (R/W) Register */ + __IO uint32_t LSTreshold; /*!< Offset: 0x044 (R/W) Register */ + __IO uint32_t RhDescriptorA; /*!< Offset: 0x048 (R/W) Register */ + __IO uint32_t RhDescriptorB; /*!< Offset: 0x04C (R/W) Register */ + __IO uint32_t RhStatus; /*!< Offset: 0x050 (R/W) Register */ + __IO uint32_t RhPortStatus1; /*!< Offset: 0x054 (R/W) Register */ + __IO uint32_t RhPortStatus2; /*!< Offset: 0x05C (R/W) Register */ + uint32_t RESERVED0[40]; + __I uint32_t Module_ID; /*!< Offset: 0x0FC (R/ ) Module ID / Version Reverence ID Register */ + /* USB On-The-Go Registers */ + __I uint32_t IntSt; /*!< Offset: 0x100 (R/ ) OTG Interrupt Status Register */ + __IO uint32_t IntEn; /*!< Offset: 0x104 (R/W) OTG Interrupt Enable Register */ + __O uint32_t IntSet; /*!< Offset: 0x108 ( /W) OTG Interrupt Set Register */ + __O uint32_t IntClr; /*!< Offset: 0x10C ( /W) OTG Interrupt Clear Register */ + __IO uint32_t StCtrl; /*!< Offset: 0x110 (R/W) OTG Status and Control Register */ + __IO uint32_t Tmr; /*!< Offset: 0x114 (R/W) OTG Timer Register */ + uint32_t RESERVED1[58]; + /* USB Device Interrupt Registers */ + __I uint32_t DevIntSt; /*!< Offset: 0x200 (R/ ) USB Device Interrupt Status Register */ + __IO uint32_t DevIntEn; /*!< Offset: 0x204 (R/W) USB Device Interrupt Enable Register */ + __O uint32_t DevIntClr; /*!< Offset: 0x208 ( /W) USB Device Interrupt Clear Register */ + __O uint32_t DevIntSet; /*!< Offset: 0x20C ( /W) USB Device Interrupt Set Register */ + /* USB Device SIE Command Registers */ + __O uint32_t CmdCode; /*!< Offset: 0x210 (R/W) USB Command Code Register */ + __I uint32_t CmdData; /*!< Offset: 0x214 (R/W) USB Command Data Register */ + /* USB Device Transfer Registers */ + __I uint32_t RxData; /*!< Offset: 0x218 (R/ ) USB Receive Data Register */ + __O uint32_t TxData; /*!< Offset: 0x21C ( /W) USB Transmit Data Register */ + __I uint32_t RxPLen; /*!< Offset: 0x220 (R/ ) USB Receive Packet Length Register */ + __O uint32_t TxPLen; /*!< Offset: 0x224 ( /W) USB Transmit Packet Length Register */ + __IO uint32_t Ctrl; /*!< Offset: 0x228 (R/W) USB Control Register */ + __O uint32_t DevIntPri; /*!< Offset: 0x22C (R/W) USB Device Interrupt Priority Register */ + /* USB Device Endpoint Interrupt Regs */ + __I uint32_t EpIntSt; /*!< Offset: 0x230 (R/ ) USB Endpoint Interrupt Status Register */ + __IO uint32_t EpIntEn; /*!< Offset: 0x234 (R/W) USB Endpoint Interrupt Enable Register */ + __O uint32_t EpIntClr; /*!< Offset: 0x238 ( /W) USB Endpoint Interrupt Clear Register */ + __O uint32_t EpIntSet; /*!< Offset: 0x23C ( /W) USB Endpoint Interrupt Set Register */ + __O uint32_t EpIntPri; /*!< Offset: 0x240 ( /W) USB Endpoint Interrupt Priority Register */ + /* USB Device Endpoint Realization Reg*/ + __IO uint32_t ReEp; /*!< Offset: 0x244 (R/W) USB Realize Endpoint Register */ + __O uint32_t EpInd; /*!< Offset: 0x248 ( /W) USB Endpoint Index Register */ + __IO uint32_t MaxPSize; /*!< Offset: 0x24C (R/W) USB MaxPacketSize Register */ + /* USB Device DMA Registers */ + __I uint32_t DMARSt; /*!< Offset: 0x250 (R/ ) USB DMA Request Status Register */ + __O uint32_t DMARClr; /*!< Offset: 0x254 ( /W) USB DMA Request Clear Register */ + __O uint32_t DMARSet; /*!< Offset: 0x258 ( /W) USB DMA Request Set Register */ + uint32_t RESERVED2[9]; + __IO uint32_t UDCAH; /*!< Offset: 0x280 (R/W) USB UDCA Head Register */ + __I uint32_t EpDMASt; /*!< Offset: 0x284 (R/ ) USB EP DMA Status Register */ + __O uint32_t EpDMAEn; /*!< Offset: 0x288 ( /W) USB EP DMA Enable Register */ + __O uint32_t EpDMADis; /*!< Offset: 0x28C ( /W) USB EP DMA Disable Register */ + __I uint32_t DMAIntSt; /*!< Offset: 0x290 (R/ ) USB DMA Interrupt Status Register */ + __IO uint32_t DMAIntEn; /*!< Offset: 0x294 (R/W) USB DMA Interrupt Enable Register */ + uint32_t RESERVED3[2]; + __I uint32_t EoTIntSt; /*!< Offset: 0x2A0 (R/ ) USB End of Transfer Interrupt Status Register */ + __O uint32_t EoTIntClr; /*!< Offset: 0x2A4 ( /W) USB End of Transfer Interrupt Clear Register */ + __O uint32_t EoTIntSet; /*!< Offset: 0x2A8 ( /W) USB End of Transfer Interrupt Set Register */ + __I uint32_t NDDRIntSt; /*!< Offset: 0x2AC (R/ ) USB New DD Request Interrupt Status Register */ + __O uint32_t NDDRIntClr; /*!< Offset: 0x2B0 ( /W) USB New DD Request Interrupt Clear Register */ + __O uint32_t NDDRIntSet; /*!< Offset: 0x2B4 ( /W) USB New DD Request Interrupt Set Register */ + __I uint32_t SysErrIntSt; /*!< Offset: 0x2B8 (R/ ) USB System Error Interrupt Status Register */ + __O uint32_t SysErrIntClr; /*!< Offset: 0x2BC ( /W) USB System Error Interrupt Clear Register */ + __O uint32_t SysErrIntSet; /*!< Offset: 0x2C0 ( /W) USB System Error Interrupt Set Register */ + uint32_t RESERVED4[15]; + /* USB OTG I2C Registers */ + union { + __I uint32_t I2C_RX; /*!< Offset: 0x300 (R/ ) OTG I2C Receive Register */ + __O uint32_t I2C_TX; /*!< Offset: 0x300 ( /W) OTG I2C Transmit Register */ + }; + __I uint32_t I2C_STS; /*!< Offset: 0x304 (R/ ) OTG I2C Status Register */ + __IO uint32_t I2C_CTL; /*!< Offset: 0x308 (R/W) OTG I2C Control Register */ + __IO uint32_t I2C_CLKHI; /*!< Offset: 0x30C (R/W) OTG I2C Clock High Register */ + __O uint32_t I2C_CLKLO; /*!< Offset: 0x310 ( /W) OTG I2C Clock Low Register */ + uint32_t RESERVED5[824]; + /* USB Clock Control Registers */ + union { + __IO uint32_t USBClkCtrl; /*!< Offset: 0xFF4 (R/W) OTG clock controller Register */ + __IO uint32_t OTGClkCtrl; /*!< Offset: 0xFF4 (R/W) USB clock controller Register */ + }; + union { + __I uint32_t USBClkSt; /*!< Offset: 0xFF8 (R/ ) OTG clock status Register */ + __I uint32_t OTGClkSt; /*!< Offset: 0xFF8 (R/ ) USB clock status Register */ + }; +} LPC_USB_TypeDef; + +/*------------- Ethernet Media Access Controller (EMAC) ----------------------*/ +/** @brief Ethernet Media Access Controller (EMAC) register structure definition */ +typedef struct +{ + __IO uint32_t MAC1; /*!< Offset: 0x000 (R/W) MAC Configuration Register 1 */ + __IO uint32_t MAC2; /*!< Offset: 0x004 (R/W) MAC Configuration Register 2 */ + __IO uint32_t IPGT; /*!< Offset: 0x008 (R/W) Back-to-Back Inter-Packet-Gap Register */ + __IO uint32_t IPGR; /*!< Offset: 0x00C (R/W) Non Back-to-Back Inter-Packet-Gap Register */ + __IO uint32_t CLRT; /*!< Offset: 0x010 (R/W) Collision Window / Retry Register */ + __IO uint32_t MAXF; /*!< Offset: 0x014 (R/W) Maximum Frame Register */ + __IO uint32_t SUPP; /*!< Offset: 0x018 (R/W) PHY Support Register */ + __IO uint32_t TEST; /*!< Offset: 0x01C (R/W) Test Register */ + __IO uint32_t MCFG; /*!< Offset: 0x020 (R/W) MII Mgmt Configuration Register */ + __IO uint32_t MCMD; /*!< Offset: 0x024 (R/W) MII Mgmt Command Register */ + __IO uint32_t MADR; /*!< Offset: 0x028 (R/W) MII Mgmt Address Register */ + __O uint32_t MWTD; /*!< Offset: 0x02C ( /W) MII Mgmt Write Data Register */ + __I uint32_t MRDD; /*!< Offset: 0x030 (R/ ) MII Mgmt Read Data Register */ + __I uint32_t MIND; /*!< Offset: 0x034 (R/ ) MII Mgmt Indicators Register */ + uint32_t RESERVED0[2]; + __IO uint32_t SA0; /*!< Offset: 0x040 (R/W) Station Address 0 Register */ + __IO uint32_t SA1; /*!< Offset: 0x044 (R/W) Station Address 1 Register */ + __IO uint32_t SA2; /*!< Offset: 0x048 (R/W) Station Address 2 Register */ + uint32_t RESERVED1[45]; + __IO uint32_t Command; /*!< Offset: 0x100 (R/W) Command Register */ + __I uint32_t Status; /*!< Offset: 0x104 (R/ ) Status Register */ + __IO uint32_t RxDescriptor; /*!< Offset: 0x108 (R/W) Receive Descriptor Base Address Register */ + __IO uint32_t RxStatus; /*!< Offset: 0x10C (R/W) Receive Status Base Address Register */ + __IO uint32_t RxDescriptorNumber; /*!< Offset: 0x110 (R/W) Receive Number of Descriptors Register */ + __I uint32_t RxProduceIndex; /*!< Offset: 0x114 (R/ ) Receive Produce Index Register */ + __IO uint32_t RxConsumeIndex; /*!< Offset: 0x118 (R/W) Receive Consume Index Register */ + __IO uint32_t TxDescriptor; /*!< Offset: 0x11C (R/W) Transmit Descriptor Base Address Register */ + __IO uint32_t TxStatus; /*!< Offset: 0x120 (R/W) Transmit Status Base Address Register */ + __IO uint32_t TxDescriptorNumber; /*!< Offset: 0x124 (R/W) Transmit Number of Descriptors Register */ + __IO uint32_t TxProduceIndex; /*!< Offset: 0x128 (R/W) Transmit Produce Index Register */ + __I uint32_t TxConsumeIndex; /*!< Offset: 0x12C (R/ ) Transmit Consume Index Register */ + uint32_t RESERVED2[10]; + __I uint32_t TSV0; /*!< Offset: 0x158 (R/ ) Transmit Status Vector 0 Register */ + __I uint32_t TSV1; /*!< Offset: 0x15C (R/ ) Transmit Status Vector 1 Register */ + __I uint32_t RSV; /*!< Offset: 0x160 (R/ ) Receive Status Vector Register */ + uint32_t RESERVED3[3]; + __IO uint32_t FlowControlCounter; /*!< Offset: 0x170 (R/W) Flow Control Counter Register */ + __I uint32_t FlowControlStatus; /*!< Offset: 0x174 (R/ ) Flow Control Status egister */ + uint32_t RESERVED4[34]; + __IO uint32_t RxFilterCtrl; /*!< Offset: 0x200 (R/W) Receive Filter Control Register */ + __I uint32_t RxFilterWoLStatus; /*!< Offset: 0x204 (R/ ) Receive Filter WoL Status Register */ + __O uint32_t RxFilterWoLClear; /*!< Offset: 0x208 ( /W) Receive Filter WoL Clear Register */ + uint32_t RESERVED5; + __IO uint32_t HashFilterL; /*!< Offset: 0x210 (R/W) Hash Filter Table LSBs Register */ + __IO uint32_t HashFilterH; /*!< Offset: 0x214 (R/W) Hash Filter Table MSBs Register */ + uint32_t RESERVED6[882]; + __I uint32_t IntStatus; /*!< Offset: 0xFE0 (R/ ) Interrupt Status Register */ + __IO uint32_t IntEnable; /*!< Offset: 0xFE4 (R/W) Interrupt Enable Register */ + __O uint32_t IntClear; /*!< Offset: 0xFE8 ( /W) Interrupt Clear Register */ + __O uint32_t IntSet; /*!< Offset: 0xFEC ( /W) Interrupt Set Register */ + uint32_t RESERVED7; + __IO uint32_t PowerDown; /*!< Offset: 0xFF4 (R/W) Power-Down Register */ +} LPC_EMAC_TypeDef; + +#if defined ( __CC_ARM ) +#pragma no_anon_unions +#endif + + +/******************************************************************************/ +/* Peripheral memory map */ +/******************************************************************************/ +/* Base addresses */ +#define LPC_FLASH_BASE (0x00000000UL) +#define LPC_RAM_BASE (0x10000000UL) +#ifdef __LPC17XX_REV00 +#define LPC_AHBRAM0_BASE (0x20000000UL) +#define LPC_AHBRAM1_BASE (0x20004000UL) +#else +#define LPC_AHBRAM0_BASE (0x2007C000UL) +#define LPC_AHBRAM1_BASE (0x20080000UL) +#endif +#define LPC_GPIO_BASE (0x2009C000UL) +#define LPC_APB0_BASE (0x40000000UL) +#define LPC_APB1_BASE (0x40080000UL) +#define LPC_AHB_BASE (0x50000000UL) +#define LPC_CM3_BASE (0xE0000000UL) + +/* APB0 peripherals */ +#define LPC_WDT_BASE (LPC_APB0_BASE + 0x00000) +#define LPC_TIM0_BASE (LPC_APB0_BASE + 0x04000) +#define LPC_TIM1_BASE (LPC_APB0_BASE + 0x08000) +#define LPC_UART0_BASE (LPC_APB0_BASE + 0x0C000) +#define LPC_UART1_BASE (LPC_APB0_BASE + 0x10000) +#define LPC_PWM1_BASE (LPC_APB0_BASE + 0x18000) +#define LPC_I2C0_BASE (LPC_APB0_BASE + 0x1C000) +#define LPC_SPI_BASE (LPC_APB0_BASE + 0x20000) +#define LPC_RTC_BASE (LPC_APB0_BASE + 0x24000) +#define LPC_GPIOINT_BASE (LPC_APB0_BASE + 0x28080) +#define LPC_PINCON_BASE (LPC_APB0_BASE + 0x2C000) +#define LPC_SSP1_BASE (LPC_APB0_BASE + 0x30000) +#define LPC_ADC_BASE (LPC_APB0_BASE + 0x34000) +#define LPC_CANAF_RAM_BASE (LPC_APB0_BASE + 0x38000) +#define LPC_CANAF_BASE (LPC_APB0_BASE + 0x3C000) +#define LPC_CANCR_BASE (LPC_APB0_BASE + 0x40000) +#define LPC_CAN1_BASE (LPC_APB0_BASE + 0x44000) +#define LPC_CAN2_BASE (LPC_APB0_BASE + 0x48000) +#define LPC_I2C1_BASE (LPC_APB0_BASE + 0x5C000) + +/* APB1 peripherals */ +#define LPC_SSP0_BASE (LPC_APB1_BASE + 0x08000) +#define LPC_DAC_BASE (LPC_APB1_BASE + 0x0C000) +#define LPC_TIM2_BASE (LPC_APB1_BASE + 0x10000) +#define LPC_TIM3_BASE (LPC_APB1_BASE + 0x14000) +#define LPC_UART2_BASE (LPC_APB1_BASE + 0x18000) +#define LPC_UART3_BASE (LPC_APB1_BASE + 0x1C000) +#define LPC_I2C2_BASE (LPC_APB1_BASE + 0x20000) +#define LPC_I2S_BASE (LPC_APB1_BASE + 0x28000) +#define LPC_RIT_BASE (LPC_APB1_BASE + 0x30000) +#define LPC_MCPWM_BASE (LPC_APB1_BASE + 0x38000) +#define LPC_QEI_BASE (LPC_APB1_BASE + 0x3C000) +#define LPC_SC_BASE (LPC_APB1_BASE + 0x7C000) + +/* AHB peripherals */ +#define LPC_EMAC_BASE (LPC_AHB_BASE + 0x00000) +#define LPC_GPDMA_BASE (LPC_AHB_BASE + 0x04000) +#define LPC_GPDMACH0_BASE (LPC_AHB_BASE + 0x04100) +#define LPC_GPDMACH1_BASE (LPC_AHB_BASE + 0x04120) +#define LPC_GPDMACH2_BASE (LPC_AHB_BASE + 0x04140) +#define LPC_GPDMACH3_BASE (LPC_AHB_BASE + 0x04160) +#define LPC_GPDMACH4_BASE (LPC_AHB_BASE + 0x04180) +#define LPC_GPDMACH5_BASE (LPC_AHB_BASE + 0x041A0) +#define LPC_GPDMACH6_BASE (LPC_AHB_BASE + 0x041C0) +#define LPC_GPDMACH7_BASE (LPC_AHB_BASE + 0x041E0) +#define LPC_USB_BASE (LPC_AHB_BASE + 0x0C000) + +/* GPIOs */ +#define LPC_GPIO0_BASE (LPC_GPIO_BASE + 0x00000) +#define LPC_GPIO1_BASE (LPC_GPIO_BASE + 0x00020) +#define LPC_GPIO2_BASE (LPC_GPIO_BASE + 0x00040) +#define LPC_GPIO3_BASE (LPC_GPIO_BASE + 0x00060) +#define LPC_GPIO4_BASE (LPC_GPIO_BASE + 0x00080) + + +/******************************************************************************/ +/* Peripheral declaration */ +/******************************************************************************/ +#define LPC_SC ((LPC_SC_TypeDef *) LPC_SC_BASE ) +#define LPC_GPIO0 ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE ) +#define LPC_GPIO1 ((LPC_GPIO_TypeDef *) LPC_GPIO1_BASE ) +#define LPC_GPIO2 ((LPC_GPIO_TypeDef *) LPC_GPIO2_BASE ) +#define LPC_GPIO3 ((LPC_GPIO_TypeDef *) LPC_GPIO3_BASE ) +#define LPC_GPIO4 ((LPC_GPIO_TypeDef *) LPC_GPIO4_BASE ) +#define LPC_WDT ((LPC_WDT_TypeDef *) LPC_WDT_BASE ) +#define LPC_TIM0 ((LPC_TIM_TypeDef *) LPC_TIM0_BASE ) +#define LPC_TIM1 ((LPC_TIM_TypeDef *) LPC_TIM1_BASE ) +#define LPC_TIM2 ((LPC_TIM_TypeDef *) LPC_TIM2_BASE ) +#define LPC_TIM3 ((LPC_TIM_TypeDef *) LPC_TIM3_BASE ) +#define LPC_RIT ((LPC_RIT_TypeDef *) LPC_RIT_BASE ) +#define LPC_UART0 ((LPC_UART_TypeDef *) LPC_UART0_BASE ) +#define LPC_UART1 ((LPC_UART1_TypeDef *) LPC_UART1_BASE ) +#define LPC_UART2 ((LPC_UART_TypeDef *) LPC_UART2_BASE ) +#define LPC_UART3 ((LPC_UART_TypeDef *) LPC_UART3_BASE ) +#define LPC_PWM1 ((LPC_PWM_TypeDef *) LPC_PWM1_BASE ) +#define LPC_I2C0 ((LPC_I2C_TypeDef *) LPC_I2C0_BASE ) +#define LPC_I2C1 ((LPC_I2C_TypeDef *) LPC_I2C1_BASE ) +#define LPC_I2C2 ((LPC_I2C_TypeDef *) LPC_I2C2_BASE ) +#define LPC_I2S ((LPC_I2S_TypeDef *) LPC_I2S_BASE ) +#define LPC_SPI ((LPC_SPI_TypeDef *) LPC_SPI_BASE ) +#define LPC_RTC ((LPC_RTC_TypeDef *) LPC_RTC_BASE ) +#define LPC_GPIOINT ((LPC_GPIOINT_TypeDef *) LPC_GPIOINT_BASE ) +#define LPC_PINCON ((LPC_PINCON_TypeDef *) LPC_PINCON_BASE ) +#define LPC_SSP0 ((LPC_SSP_TypeDef *) LPC_SSP0_BASE ) +#define LPC_SSP1 ((LPC_SSP_TypeDef *) LPC_SSP1_BASE ) +#define LPC_ADC ((LPC_ADC_TypeDef *) LPC_ADC_BASE ) +#define LPC_DAC ((LPC_DAC_TypeDef *) LPC_DAC_BASE ) +#define LPC_CANAF_RAM ((LPC_CANAF_RAM_TypeDef *) LPC_CANAF_RAM_BASE) +#define LPC_CANAF ((LPC_CANAF_TypeDef *) LPC_CANAF_BASE ) +#define LPC_CANCR ((LPC_CANCR_TypeDef *) LPC_CANCR_BASE ) +#define LPC_CAN1 ((LPC_CAN_TypeDef *) LPC_CAN1_BASE ) +#define LPC_CAN2 ((LPC_CAN_TypeDef *) LPC_CAN2_BASE ) +#define LPC_MCPWM ((LPC_MCPWM_TypeDef *) LPC_MCPWM_BASE ) +#define LPC_QEI ((LPC_QEI_TypeDef *) LPC_QEI_BASE ) +#define LPC_EMAC ((LPC_EMAC_TypeDef *) LPC_EMAC_BASE ) +#define LPC_GPDMA ((LPC_GPDMA_TypeDef *) LPC_GPDMA_BASE ) +#define LPC_GPDMACH0 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH0_BASE ) +#define LPC_GPDMACH1 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH1_BASE ) +#define LPC_GPDMACH2 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH2_BASE ) +#define LPC_GPDMACH3 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH3_BASE ) +#define LPC_GPDMACH4 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH4_BASE ) +#define LPC_GPDMACH5 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH5_BASE ) +#define LPC_GPDMACH6 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH6_BASE ) +#define LPC_GPDMACH7 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH7_BASE ) +#define LPC_USB ((LPC_USB_TypeDef *) LPC_USB_BASE ) + +/** + * @} + */ + +#endif // __LPC17xx_H__ diff --git a/os/hal/platforms/LPC17xx/adc_lld.c b/os/hal/platforms/LPC17xx/adc_lld.c new file mode 100644 index 000000000..2363dd12f --- /dev/null +++ b/os/hal/platforms/LPC17xx/adc_lld.c @@ -0,0 +1,284 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/adc_lld.c + * @brief LPC17xx ADC subsystem low level driver source. + * @note Values in samples buffer are from DR register. + * To get ADC values make conversion (DR >> 6) & 0x03FF. + * @addtogroup ADC + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +ADCDriver ADCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if LPC17xx_ADC_USE_DMA +/** + * @brief Common IRQ handler. + * + * @param[in] adcp pointer to the @p ADCDriver object + */ +static void adc_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) { + (void) flags; + + adcp->num++; + if (adcp->num == 1) { + dmaChannelSrcAddr(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.srcaddr); + dmaChannelDstAddr(LPC17xx_ADC_DMA_CHANNEL, \ + &adcp->samples[adcp->nsamples/2]); + dmaChannelControl(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.control); + dmaChannelConfig(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.config); + _adc_isr_half_code(adcp); + + } + else { + adcp->num = 0; + if (adcp->grpp->circular == TRUE) { + dmaChannelSrcAddr(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.srcaddr); + dmaChannelDstAddr(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.dstaddr); + dmaChannelControl(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.control); + dmaChannelConfig(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.config); + } + _adc_isr_full_code(adcp); + } +} +#endif +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief ADC interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector98) { + uint32_t status; + uint32_t n; + uint8_t i; + + CH_IRQ_PROLOGUE(); + status = LPC_ADC->STAT; + + n = ADCD1.num; + + /* Note, an overrun may occur only in burst mode, if one or more + conversions was (were) lost. */ + if ((status & ADC0STAT_OVERRUN_MASK)) { + if (ADCD1.grpp != NULL) + _adc_isr_error_code(&ADCD1, ADC_ERR_OVERRUN); + } + else { + + status = status & ADC0STAT_DONE_MASK; + for (i = 0; i < ADC_MAX_CHANNELS; i++) { + if (status & (0x01 << i)) { + ADCD1.samples[n] = LPC_ADC->DR[i]; + n++; + } + } + + if (n == (ADCD1.nsamples / 2)) { + _adc_isr_half_code(&ADCD1); + } + + if (n == ADCD1.nsamples) { + n = 0; + _adc_isr_full_code(&ADCD1); + } + } + ADCD1.num = n; + CH_IRQ_EPILOGUE(); +} + + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adc = LPC_ADC; + +#if LPC17xx_ADC_USE_DMA + nvicDisableVector(ADC_IRQn); +#else + nvicEnableVector(ADC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_ADC_IRQ_PRIORITY)); +#endif +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* If in stopped state then enables the ADC. */ + if (adcp->state == ADC_STOP) { + LPC_SC->PCONP |= (1UL << 12); /* Enable ADC power */ + +#if LPC17xx_ADC_USE_DMA + dmaChannelAllocate(LPC17xx_ADC_DMA_CHANNEL, \ + (lpc17xx_dmaisr_t)adc_serve_dma_interrupt, \ + (void *)adcp); +#endif + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock.*/ + if (adcp->state == ADC_READY) { + adcp->adc->CR = 0; /* Clear PDN bit */ + LPC_SC->PCONP &= ~(1UL << 12); /* Disable ADC power */ + +#if LPC17xx_ADC_USE_DMA + dmaChannelRelease(LPC17xx_ADC_DMA_CHANNEL); +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + + uint32_t dummy; + uint32_t cr; + uint8_t i; +#if LPC17xx_ADC_USE_DMA + uint8_t ch; +#endif + + cr = adcp->grpp->cr0; + adcp->num = 0; + adcp->nsamples = adcp->depth * adcp->grpp->num_channels; + + for (i = 0; i < ADC_MAX_CHANNELS; i++) { + dummy = adcp->adc->DR[i]; /* Clear all DONE and OVERRUN flags. */ + } + +#if LPC17xx_ADC_USE_DMA + ch = 0; + for (i = 0; i < 8; i++) { + if (cr & (1UL << i)) { + ch = i; /* Get enabled channel number */ + break; + } + } + + /* DMA configuration */ + adcp->adc_dma_cfg.srcaddr = (uint32_t)&adcp->adc->DR[ch]; + adcp->adc_dma_cfg.dstaddr = (uint32_t)&adcp->samples[0]; + adcp->adc_dma_cfg.lli = 0; + adcp->adc_dma_cfg.control = + DMA_CTRL_TRANSFER_SIZE(adcp->nsamples/2) | + DMA_CTRL_SRC_BSIZE_1 | + DMA_CTRL_DST_BSIZE_1 | + DMA_CTRL_SRC_WIDTH_WORD | + DMA_CTRL_DST_WIDTH_WORD | + DMA_CTRL_SRC_NOINC | + DMA_CTRL_DST_INC | + DMA_CTRL_PROT1_USER | + DMA_CTRL_PROT2_NONBUFF | + DMA_CTRL_PROT3_NONCACHE | + DMA_CTRL_INT; + + adcp->adc_dma_cfg.config = + DMA_CFG_CH_ENABLE | + DMA_CFG_SRC_PERIPH(DMA_ADC) | + DMA_CFG_TTYPE_P2M | + DMA_CFG_IE | + DMA_CFG_ITC; + + dmaChannelSrcAddr(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.srcaddr); + dmaChannelDstAddr(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.dstaddr); + dmaChannelControl(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.control); + dmaChannelConfig(LPC17xx_ADC_DMA_CHANNEL, adcp->adc_dma_cfg.config); +#endif + + /* ADC configuration and conversion start. */ + adcp->adc->INTEN = adcp->grpp->inten; /* Set ADC interrupt on selected channels */ + adcp->adc->CR = (cr & 0x0000FFFF) | ((LPC17xx_ADC_CLKDIV - 1) << 8) | AD0CR_PDN; + adcp->adc->CR |= cr & 0xFFFF0000; + +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + +#if LPC17xx_ADC_USE_DMA + dmaChannelDisable(LPC17xx_ADC_DMA_CHANNEL); +#endif + adcp->adc->CR &= ~(AD0CR_MODE_BURST | AD0CR_START_MASK); /* Disable ADC conversion. */ + adcp->adc->INTEN = 0; /* Mask ADC interrupts. */ +} + + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/adc_lld.h b/os/hal/platforms/LPC17xx/adc_lld.h new file mode 100644 index 000000000..0f13cd731 --- /dev/null +++ b/os/hal/platforms/LPC17xx/adc_lld.h @@ -0,0 +1,346 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/adc_lld.h + * @brief LPC17xx ADC subsystem low level driver header. + * @note Values in samples buffer are from DR register. + * To get ADC values make conversion (DR >> 6) & 0x03FF. + * @addtogroup ADC + * @{ + */ + +#ifndef _ADC_LLD_H_ +#define _ADC_LLD_H_ + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define ADC0STAT_DONE_MASK 0x000000FF +#define ADC0STAT_OVERRUN_MASK 0x0000FF00 + +#define AD0CR_PDN (1UL << 21) +/** + * @name Absolute Maximum Ratings + * @{ + */ + +/** + * @brief Maximum ADC clock frequency. + */ +#define LPC17xx_ADCCLK_MAX 13000000 + +/** + * @brief Available number of ADC channels. + */ +#define ADC_MAX_CHANNELS 8 +/** @} */ + +/** + * @name ADC settings + * @{ + */ + +/** + * @name Available analog channels + * @note In software-controlled mode only + * one channel can be selected. + * @{ + */ +#define AD0CR_CHANNEL0 (1UL << 0) +#define AD0CR_CHANNEL1 (1UL << 1) +#define AD0CR_CHANNEL2 (1UL << 2) +#define AD0CR_CHANNEL3 (1UL << 3) +#define AD0CR_CHANNEL4 (1UL << 4) +#define AD0CR_CHANNEL5 (1UL << 5) +#define AD0CR_CHANNEL6 (1UL << 6) +#define AD0CR_CHANNEL7 (1UL << 7) +/** @} */ + +/** + * @name ADC mode types + * @note In software-controlled mode only one conversion + * is make + * @{ + */ +#define AD0CR_MODE_SOFT (0UL << 16) +#define AD0CR_MODE_BURST (1UL << 16) +/** @} */ + +/** + * @name Triggers selection + * @note Only use in software-controlled mode + * @{ + */ +#define AD0CR_START_NO (0UL << 24) +#define AD0CR_START_NOW (1UL << 24) +#define AD0CR_START_CT16B0_CAP0 (2UL << 24) +#define AD0CR_START_CT32B0_CAP0 (3UL << 24) +#define AD0CR_START_CT32B0_MAT0 (4UL << 24) +#define AD0CR_START_CT32B0_MAT1 (5UL << 24) +#define AD0CR_START_CT16B0_MAT0 (6UL << 24) +#define AD0CR_START_CT16B0_MAT1 (7UL << 24) +#define AD0CR_START_MASK (7UL << 24) +/** @} */ + +/** + * @name Trigger edge type selection + * @note Only use in software-controlled mode. + * @{ + */ +#define AD0CR_EDGE_RISSING (0UL << 27) +#define AD0CR_EDGE_FALLING (1UL << 27) +/** @} */ +/** @} */ +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ADC common clock divider. + */ +#if !defined(LPC17xx_ADC_CLKDIV) || defined(__DOXYGEN__) +#define LPC17xx_ADC_CLKDIV 12 +#endif + +#if LPC17xx_PCLK/LPC17xx_ADC_CLKDIV > LPC17xx_ADCCLK_MAX +#error "ADC clock frequency out of the acceptable range (13MHz max)" +#endif + +/** + * @brief ADC interrupt priority level setting. + */ +#if !defined(LPC17xx_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_ADC_IRQ_PRIORITY 3 +#endif + +/** + * @brief ADC DMA enable switch. + * @details If set to @p TRUE the support for ADC DMA is included. + * @note ADC DMA only support one selected channel. The default is @p FALSE. + */ +#if !defined(LPC17xx_ADC_USE_DMA) || defined(__DOXYGEN__) +#define LPC17xx_ADC_USE_DMA FALSE +#endif + +#if LPC17xx_ADC_USE_DMA || defined(__DOXYGEN__) +#if !defined(LPC17xx_DMA_REQUIRED) +#define LPC17xx_DMA_REQUIRED +#endif +#endif + +/** + * @brief ADC DMA channel. + */ +#if !defined(LPC17xx_ADC_DMA_CHANNEL) || defined(__DOXYGEN__) +#define LPC17xx_ADC_DMA_CHANNEL DMA_CHANNEL6 +#endif +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +typedef uint32_t adcsample_t; + +/** + * @brief Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_OVERRUN = 1 /**< ADC overrun condition. */ +} adcerror_t; + +/** + * @brief Type of a structure representing an ADC driver. + */ +typedef struct ADCDriver ADCDriver; + +/** + * @brief ADC notification callback type. + * + * @param[in] adcp pointer to the @p ADCDriver object triggering the + * callback + * @param[in] buffer pointer to the most recent samples data + * @param[in] n number of buffer rows available starting from @p buffer + */ +typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n); + +/** + * @brief ADC error callback type. + * + * @param[in] adcp pointer to the @p ADCDriver object triggering the + * callback + * @param[in] err ADC error code + */ +typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); + +/** + * @brief Conversion group configuration structure. + * @details This implementation-dependent structure describes a conversion + * operation. + * @note The use of this configuration structure requires knowledge of + * LPC17xx ADC cell registers interface, please refer to the LPC17xx + * reference manual for details. + */ +typedef struct { + /** + * @brief Enables the circular buffer mode for the group. + */ + bool_t circular; + /** + * @brief Number of the analog channels belonging to the conversion group. + */ + adc_channels_num_t num_channels; + /** + * @brief Callback function associated to the group or @p NULL. + */ + adccallback_t end_cb; + /** + * @brief Error callback or @p NULL. + */ + adcerrorcallback_t error_cb; + /* End of the mandatory fields.*/ + /** + * @brief ADC CR0 register initialization data. + * @note All the required bits must be defined into this field. + */ + uint32_t cr0; + /** + * @brief ADC INTENT register initialization data. + * @note In interrupt burst mode only define interrupt for + * last enabled channel. + */ + uint32_t inten; +} ADCConversionGroup; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + uint32_t dummy; +} ADCConfig; + +/** + * @brief Structure representing an ADC driver. + */ +struct ADCDriver { + /** + * @brief Driver state. + */ + adcstate_t state; + /** + * @brief Current configuration data. + */ + const ADCConfig *config; + /** + * @brief Current samples buffer pointer or @p NULL. + */ + adcsample_t *samples; + /** + * @brief Current samples buffer depth or @p 0. + */ + size_t depth; + /** + * @brief Current conversion group pointer or @p NULL. + */ + const ADCConversionGroup *grpp; +#if ADC_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + Thread *thread; +#endif +#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + Mutex mutex; +#elif CH_USE_SEMAPHORES + Semaphore semaphore; +#endif +#endif /* ADC_USE_MUTUAL_EXCLUSION */ +#if defined(ADC_DRIVER_EXT_FIELDS) + ADC_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the ADCx registers block. + */ + LPC_ADC_TypeDef *adc; + /** + * @brief Number of all samples in buffer. + */ + uint32_t nsamples; + /** + * @brief Samples buffer counter. + */ + uint32_t num; +#if LPC17xx_ADC_USE_DMA + /** + * @brief ADC DMA configuration structure. + */ + lpc17xx_dma_channel_config_t adc_dma_cfg; +#endif +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* _ADC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/gpt_lld.c b/os/hal/platforms/LPC17xx/gpt_lld.c new file mode 100644 index 000000000..fada91b20 --- /dev/null +++ b/os/hal/platforms/LPC17xx/gpt_lld.c @@ -0,0 +1,338 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/gpt_lld.c + * @brief LPC17xx GPT subsystem low level driver source. + * + * @addtogroup GPT + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief GPT1 driver identifier. + * @note The driver GPT1 allocates the complex timer TIM0 when enabled. + */ +#if LPC17xx_GPT_USE_TIM0 || defined(__DOXYGEN__) +GPTDriver GPTD1; +#endif + +/** + * @brief GPT2 driver identifier. + * @note The driver GPT2 allocates the timer TIM1 when enabled. + */ +#if LPC17xx_GPT_USE_TIM1 || defined(__DOXYGEN__) +GPTDriver GPTD2; +#endif + +/** + * @brief GPT3 driver identifier. + * @note The driver GPT3 allocates the timer TIM2 when enabled. + */ +#if LPC17xx_GPT_USE_TIM2 || defined(__DOXYGEN__) +GPTDriver GPTD3; +#endif + +/** + * @brief GPT4 driver identifier. + * @note The driver GPT4 allocates the timer TIM3 when enabled. + */ +#if LPC17xx_GPT_USE_TIM3 || defined(__DOXYGEN__) +GPTDriver GPTD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared IRQ handler. + * + * @param[in] gptp pointer to a @p GPTDriver object + */ +static void gpt_lld_serve_interrupt(GPTDriver *gptp) { + + gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/ + if (gptp->state == GPT_ONESHOT) { + gptp->state = GPT_READY; /* Back in GPT_READY state. */ + gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */ + } + gptp->config->callback(gptp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC17xx_GPT_USE_TIM0 +/** + * @brief TIM0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector44) { + + CH_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD1); + + CH_IRQ_EPILOGUE(); +} +#endif /* LPC17xx_GPT_USE_TIM0 */ + +#if LPC17xx_GPT_USE_TIM1 +/** + * @brief TIM1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector48) { + + CH_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD2); + + CH_IRQ_EPILOGUE(); +} +#endif /* LPC17xx_GPT_USE_TIM0 */ + +#if LPC17xx_GPT_USE_TIM2 +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector4C) { + + CH_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD3); + + CH_IRQ_EPILOGUE(); +} +#endif /* LPC17xx_GPT_USE_TIM2 */ + +#if LPC17xx_GPT_USE_TIM3 +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector50) { + + CH_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD4); + + CH_IRQ_EPILOGUE(); +} +#endif /* LPC17xx_GPT_USE_TIM3 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level GPT driver initialization. + * + * @notapi + */ +void gpt_lld_init(void) { + +#if LPC17xx_GPT_USE_TIM0 + /* Driver initialization.*/ + GPTD1.tmr = LPC_TIM0; + gptObjectInit(&GPTD1); +#endif + +#if LPC17xx_GPT_USE_TIM1 + /* Driver initialization.*/ + GPTD2.tmr = LPC_TIM1; + gptObjectInit(&GPTD2); +#endif + +#if LPC17xx_GPT_USE_TIM2 + /* Driver initialization.*/ + GPTD3.tmr = LPC_TIM2; + gptObjectInit(&GPTD3); +#endif + +#if LPC17xx_GPT_USE_TIM3 + /* Driver initialization.*/ + GPTD4.tmr = LPC_TIM3; + gptObjectInit(&GPTD4); +#endif +} + +/** + * @brief Configures and activates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_start(GPTDriver *gptp) { + uint32_t pr; + + if (gptp->state == GPT_STOP) { + /* Clock activation.*/ +#if LPC17xx_GPT_USE_TIM0 + if (&GPTD1 == gptp) { + LPC_SC->PCONP |= (1UL << 1); + nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(2)); + } +#endif +#if LPC17xx_GPT_USE_TIM1 + if (&GPTD2 == gptp) { + LPC_SC->PCONP |= (1UL << 2); + nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(3)); + } +#endif +#if LPC17xx_GPT_USE_TIM2 + if (&GPTD3 == gptp) { + LPC_SC->PCONP |= (1UL << 22); + nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(2)); + } +#endif +#if LPC17xx_GPT_USE_TIM3 + if (&GPTD4 == gptp) { + LPC_SC->PCONP |= (1UL << 23); + nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(2)); + } +#endif + } + + /* Prescaler value calculation.*/ + pr = (uint16_t)((LPC17xx_PCLK/ gptp->config->frequency) - 1); + chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC17xx_PCLK, + "gpt_lld_start(), #1", "invalid frequency"); + + /* Timer configuration.*/ + gptp->tmr->PR = pr; + gptp->tmr->IR = 1; + gptp->tmr->MCR = 0; + gptp->tmr->TCR = 0; +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop(GPTDriver *gptp) { + + if (gptp->state == GPT_READY) { + gptp->tmr->MCR = 0; + gptp->tmr->TCR = 0; + +#if LPC17xx_GPT_USE_TIM0 + if (&GPTD1 == gptp) { + nvicDisableVector(TIMER0_IRQn); + LPC_SC->PCONP &= ~(1UL << 1); + } +#endif +#if LPC17xx_GPT_USE_TIM1 + if (&GPTD2 == gptp) { + nvicDisableVector(TIMER1_IRQn); + LPC_SC->PCONP &= ~(1UL << 2); + } +#endif +#if LPC17xx_GPT_USE_TIM2 + if (&GPTD3 == gptp) { + nvicDisableVector(TIMER2_IRQn); + LPC_SC->PCONP &= ~(1UL << 22); + } +#endif +#if LPC17xx_GPT_USE_TIM3 + if (&GPTD4 == gptp) { + nvicDisableVector(TIMER3_IRQn); + LPC_SC->PCONP &= ~(1UL << 23); + } +#endif + } +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @notapi + */ +void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) { + + gptp->tmr->MR0 = interval - 1; + gptp->tmr->IR = 1; + gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */ + gptp->tmr->TCR = 2; /* Reset counter and prescaler. */ + gptp->tmr->TCR = 1; /* Timer enabled. */ +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop_timer(GPTDriver *gptp) { + + gptp->tmr->IR = 1; + gptp->tmr->MCR = 0; + gptp->tmr->TCR = 0; +} + +/** + * @brief Starts the timer in one shot mode and waits for completion. + * @details This function specifically polls the timer waiting for completion + * in order to not have extra delays caused by interrupt servicing, + * this function is only recommended for short delays. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @notapi + */ +void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) { + + gptp->tmr->MR0 = interval - 1; + gptp->tmr->IR = 1; + gptp->tmr->MCR = 4; /* Stop TC on match MR0. */ + gptp->tmr->TCR = 2; /* Reset counter and prescaler. */ + gptp->tmr->TCR = 1; /* Timer enabled. */ + while (gptp->tmr->TCR & 1) + ; +} + +#endif /* HAL_USE_GPT */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/gpt_lld.h b/os/hal/platforms/LPC17xx/gpt_lld.h new file mode 100644 index 000000000..09304536e --- /dev/null +++ b/os/hal/platforms/LPC17xx/gpt_lld.h @@ -0,0 +1,208 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/gpt_lld.h + * @brief LPC17xx GPT subsystem low level driver header. + * + * @addtogroup GPT + * @{ + */ + +#ifndef _GPT_LLD_H_ +#define _GPT_LLD_H_ + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief GPT1 driver enable switch. + * @details If set to @p TRUE the support for GPT1 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_GPT_USE_TIM0) || defined(__DOXYGEN__) +#define LPC17xx_GPT_USE_TIM0 TRUE +#endif + +/** + * @brief GPT2 driver enable switch. + * @details If set to @p TRUE the support for GPT2 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_GPT_USE_TIM1) || defined(__DOXYGEN__) +#define LPC17xx_GPT_USE_TIM1 TRUE +#endif + +/** + * @brief GPT3 driver enable switch. + * @details If set to @p TRUE the support for GPT3 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_GPT_USE_TIM2) || defined(__DOXYGEN__) +#define LPC17xx_GPT_USE_TIM2 TRUE +#endif + +/** + * @brief GPT4 driver enable switch. + * @details If set to @p TRUE the support for GPT4 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_GPT_USE_TIM3) || defined(__DOXYGEN__) +#define LPC17xx_GPT_USE_TIM3 TRUE +#endif + +/** + * @brief GPT1 interrupt priority level setting. + */ +#if !defined(LPC17xx_GPT_TIM0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_GPT_TIM0_IRQ_PRIORITY 2 +#endif + +/** + * @brief GPT2 interrupt priority level setting. + */ +#if !defined(LPC17xx_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_GPT_TIM1_IRQ_PRIORITY 2 +#endif + +/** + * @brief GPT3 interrupt priority level setting. + */ +#if !defined(LPC17xx_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_GPT_TIM2_IRQ_PRIORITY 2 +#endif + +/** + * @brief GPT4 interrupt priority level setting. + */ +#if !defined(LPC17xx_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_GPT_TIM3_IRQ_PRIORITY 2 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !LPC17xx_GPT_USE_TIM0 && !LPC17xx_GPT_USE_TIM1 && \ + !LPC17xx_GPT_USE_TIM2 && !LPC17xx_GPT_USE_TIM3 +#error "GPT driver activated but no CT peripheral assigned" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief GPT frequency type. + */ +typedef uint32_t gptfreq_t; + +/** + * @brief GPT counter type. + */ +typedef uint32_t gptcnt_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + gptfreq_t frequency; + /** + * @brief Timer callback pointer. + * @note This callback is invoked on GPT counter events. + */ + gptcallback_t callback; + /* End of the mandatory fields.*/ +} GPTConfig; + +/** + * @brief Structure representing a GPT driver. + */ +struct GPTDriver { + /** + * @brief Driver state. + */ + gptstate_t state; + /** + * @brief Current configuration data. + */ + const GPTConfig *config; + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the CTxxBy registers block. + */ + LPC_TIM_TypeDef *tmr; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC17xx_GPT_USE_TIM0 && !defined(__DOXYGEN__) +extern GPTDriver GPTD1; +#endif + +#if LPC17xx_GPT_USE_TIM1 && !defined(__DOXYGEN__) +extern GPTDriver GPTD2; +#endif + +#if LPC17xx_GPT_USE_TIM2 && !defined(__DOXYGEN__) +extern GPTDriver GPTD3; +#endif + +#if LPC17xx_GPT_USE_TIM3 && !defined(__DOXYGEN__) +extern GPTDriver GPTD4; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void gpt_lld_init(void); + void gpt_lld_start(GPTDriver *gptp); + void gpt_lld_stop(GPTDriver *gptp); + void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period); + void gpt_lld_stop_timer(GPTDriver *gptp); + void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_GPT */ + +#endif /* _GPT_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/hal_lld.c b/os/hal/platforms/LPC17xx/hal_lld.c new file mode 100644 index 000000000..b5190d81c --- /dev/null +++ b/os/hal/platforms/LPC17xx/hal_lld.c @@ -0,0 +1,158 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/hal_lld.c + * @brief LPC17xx HAL subsystem low level driver source. + * + * @addtogroup HAL + * @{ + */ + +#include "ch.h" +#include "hal.h" + +/** + * @brief Register missing in NXP header file. + */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level HAL driver initialization. + * + * @notapi + */ +void hal_lld_init(void) { + + /* SysTick initialization using the system clock.*/ + nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_SYSTICK); + SysTick->LOAD = LPC17xx_CCLK / CH_FREQUENCY - 1; + SysTick->VAL = 0; + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_ENABLE_Msk | + SysTick_CTRL_TICKINT_Msk; + + /* DWT cycle counter enable.*/ + SCS_DEMCR |= SCS_DEMCR_TRCENA; + DWT_CTRL |= DWT_CTRL_CYCCNTENA; + +#if defined(LPC17xx_DMA_REQUIRED) + dmaInit(); +#endif +} + +/** + * @brief LPC17xx clocks and PLL initialization. + * @note All the involved constants come from the file @p board.h. + * @note This function must be invoked only after the system reset. + * + * @special + */ +void LPC17xx_clock_init(void) { + + /* Flash wait states setting, the code takes care to not touch TBD bits.*/ + LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~(0x0000000F << 12)) | (LPC17xx_FLASHCFG_FLASHTIM << 12); + + /* System oscillator initialization if required.*/ + +#if LPC17xx_MAINOSC_ENABLE + LPC_SC->SCS = (1 << 5) | (LPC17xx_OSCRANGE << 4); /* Enable Main oscillator */ + while (!(LPC_SC->SCS & (1 << 6))) + ; /* Wait for main oscillator to be ready */ +#endif + + /* Peripheral clock divider initialization, must be set before enabling Main PLL (PLL0). + Read errata sheet ES_LPC176x. */ + LPC_SC->PCLKSEL0 = LPC17xx_PCLKSEL0; + LPC_SC->PCLKSEL1 = LPC17xx_PCLKSEL1; + + LPC_SC->CCLKCFG = LPC17xx_CCLK_DIV - 1; /* Set CPU clock divider */ + + LPC_SC->CLKSRCSEL = LPC17xx_SYSCLK_SELECT; /* Select clock source for PLL0 if enabled or CPU */ + +#if LPC17xx_MAINPLL_ENABLE + + /* PLL0 configuration and start */ + LPC_SC->PLL0CFG = (LPC17xx_PLL0CFG_NSEL0 << 16) | LPC17xx_PLL0CFG_MSEL0; + LPC_SC->PLL0FEED = 0xAA; + LPC_SC->PLL0FEED = 0x55; + + LPC_SC->PLL0CON = 0x01; /* Enable PLL0. */ + LPC_SC->PLL0FEED = 0xAA; + LPC_SC->PLL0FEED = 0x55; + while (!(LPC_SC->PLL0STAT & (1UL << 26))) + ; /* Wait for PLL0 locked */ + + LPC_SC->PLL0CON = 0x03; /* Enable and Connect PLL0. */ + LPC_SC->PLL0FEED = 0xAA; + LPC_SC->PLL0FEED = 0x55; + while (!(LPC_SC->PLL0STAT & ((1UL << 25) | (1UL << 24)))) + ; /* Wait for PLL0 connected */ + +#endif /* LPC17xx_MAINPLL_ENABLE == TRUE */ + +#if LPC17xx_USBPLL_ENABLE + /* PLL1 configuration and start */ + LPC_SC->PLL1CFG = (LPC17xx_PLL1CFG_PSEL1 << 5) | LPC17xx_PLL1CFG_MSEL1; + LPC_SC->PLL1FEED = 0xAA; + LPC_SC->PLL1FEED = 0x55; + + LPC_SC->PLL1CON = 0x01; /* Enable PLL1. */ + LPC_SC->PLL1FEED = 0xAA; + LPC_SC->PLL1FEED = 0x55; + while (!(LPC_SC->PLL1STAT & (1UL << 10))) + ; /* Wait for PLL1 locked */ + + LPC_SC->PLL1CON = 0x03; /* Enable and Connect PLL1. */ + LPC_SC->PLL1FEED = 0xAA; + LPC_SC->PLL1FEED = 0x55; + while (!(LPC_SC->PLL1STAT & ((1UL << 9) | (1UL << 8)))) + ; /* Wait for PLL1 connected */ +#endif /* LPC17xx_USBPLL_ENABLE == TRUE */ + +#if !LPC17xx_USBPLL_ENABLE && HAL_USE_USB + LPC_SC->USBCLKCFG = LPC17xx_USBCLKPLL0_SELECT; +#endif + + /* Power control configuration */ + LPC_SC->PCONP = (1 << 15) | (1 << 9); /* Enable power for GPIO and RTC */ + +#if LPC17xx_CLKOUT_ENABLE + LPC_SC->CLKOUTCFG = (1UL << 8) | ((LPC17xx_CLKOUT_DIV - 1) << 4) | LPC17xx_CLKOUT_SELECT; +#endif +} + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/hal_lld.h b/os/hal/platforms/LPC17xx/hal_lld.h new file mode 100644 index 000000000..23a0e3574 --- /dev/null +++ b/os/hal/platforms/LPC17xx/hal_lld.h @@ -0,0 +1,433 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/hal_lld.h + * @brief HAL subsystem low level driver header template. + * + * @addtogroup HAL + * @{ + */ + +#ifndef _HAL_LLD_H_ +#define _HAL_LLD_H_ + +#include "LPC17xx.h" +#include "nvic.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Defines the support for realtime counters in the HAL. + */ +#define HAL_IMPLEMENTS_COUNTERS TRUE + +/** + * @brief Platform name. + */ +#define PLATFORM_NAME "LPC17xx" + +#define IRCOSCCLK 4000000UL /**< High speed internal clock. */ + +#define CLKSRCSEL_IRCOSC 0UL /**< Clock source is IRC. */ +#define CLKSRCSEL_MAINOSC 1UL /**< Clock source is Main oscillator. */ +#define CLKSRCSEL_RTCOSC 2UL /**< Clock source is RTC oscillator. */ + +#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock source is CCLK/4 */ +#define PCLKSEL_CCLK 1UL /**< Peripheral clock source is CCLK */ +#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock source is CCLK/2 */ +#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock source is CCLK/8 */ +#define PCLKSEL_MASK 3UL + +#define CLKOUTSEL_CCLK 0UL /**< Clock output is CPU clock. */ +#define CLKOUTSEL_MAINOSC 1UL /**< Clock output is Main oscillator. */ +#define CLKOUTSEL_IRCOSC 2UL /**< Clock output is IRC oscillator. */ +#define CLKOUTSEL_USBCLK 3UL /**< Clock output is USB clock. */ +#define CLKOUTSEL_RTCOSC 4UL /**< Clock output is RTC oscillator. */ + +#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock output is CCLK/4 */ +#define PCLKSEL_CCLK 1UL /**< Peripheral clock output is CCLK */ +#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock output is CCLK/2 */ +#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock output is CCLK/8 */ + +#define USBSEL_PLL0_DIV_6 5UL /**< USB clock source is PLL0/6. */ +#define USBSEL_PLL0_DIV_7 7UL /**< USB clock source is PLL0/7. */ +#define USBSEL_PLL0_DIV_9 9UL /**< USB clock source is PLL0/9. */ +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Main oscillator enable. + */ +#if !defined(LPC17xx_MAINOSC_ENABLE) || defined(__DOXYGEN__) +#define LPC17xx_MAINOSC_ENABLE TRUE +#endif + +/** + * @brief System PLL clock source select. + */ +#if !defined(LPC17xx_SYSCLK_SELECT) || defined(__DOXYGEN__) +#define LPC17xx_SYSCLK_SELECT CLKSRCSEL_MAINOSC +#endif + +/** + * @brief Main PLL enable. + */ +#if !defined(LPC17xx_MAINPLL_ENABLE) || defined(__DOXYGEN__) +#define LPC17xx_MAINPLL_ENABLE TRUE +#endif + +/** + * @brief Main PLL multiplier. + * @note Final frequency must not exceed the CCO ratings. + */ +#if !defined(LPC17xx_MAINPLL_MUL) || defined(__DOXYGEN__) +#define LPC17xx_MAINPLL_MUL 200 +#endif + +/** + * @brief Main PLL pre-divider. + * @note The value must be in the 1..32 range and the final frequency + * must not exceed the CCO ratings. + */ +#if !defined(LPC17xx_MAINPLL_PREDIV) || defined(__DOXYGEN__) +#define LPC17xx_MAINPLL_PREDIV 6 +#endif + +/** + * @brief USB PLL enable. + */ +#if !defined(LPC17xx_USBPLL_ENABLE) || defined(__DOXYGEN__) +#define LPC17xx_USBPLL_ENABLE FALSE +#endif + +/** + * @brief USB PLL multiplier. + * @note The value must be in the 1..32 range and the final frequency + * must not exceed the CCO ratings and USB clock must be equal 48MHz. + */ +#if !defined(LPC17xx_USBPLL_MUL) || defined(__DOXYGEN__) +#define LPC17xx_USBPLL_MUL 4 +#endif + +/** + * @brief USB PLL divider. + * @note The value must be 2, 4, 8 or 16 and the final frequency + * must not exceed the CCO ratings and USB clock must be equal 48MHz. + */ +#if !defined(LPC17xx_USBPLL_DIV) || defined(__DOXYGEN__) +#define LPC17xx_USBPLL_DIV 4 +#endif + +/** + * @brief CPU clock divider. + * @note The value must be chosen between (1...255). + */ +#if !defined(LPC17xx_CCLK_DIV) || defined(__DOXYGEN__) +#define LPC17xx_CCLK_DIV 4 +#endif + +/** + * @brief PCLK clock select. + */ +#if !defined(LPC17xx_PCLK_SELECT) || defined(__DOXYGEN__) +#define LPC17xx_PCLK_SELECT PCLKSEL_CCLK +#endif + +/** + * @brief Clock output enable. + * @note + */ +#if !defined(LPC17xx_CLKOUT_ENABLE) || defined(__DOXYGEN__) +#define LPC17xx_CLKOUT_ENABLE FALSE +#endif + +/** + * @brief Clock output divider. + * @note The value must be chosen between (1...16). + */ +#if !defined(LPC17xx_CLKOUT_DIV) || defined(__DOXYGEN__) +#define LPC17xx_CLKOUT_DIV 4 +#endif + +/** + * @brief Clock output clock source select. + */ +#if !defined(LPC17xx_CLKOUT_SELECT) || defined(__DOXYGEN__) +#define LPC17xx_CLKOUT_SELECT CLKOUTSEL_MAINOSC +#endif + +/** + * @brief USB clock PPL0 clock source select. + * @note PLL0 output must be 288MHz (USBSEL_PLL0_DIV_6), 384MHz (USBSEL_PLL0_DIV_8) or + * 480MHz(USBSEL_PLL0_DIV_10). Only is used when USB PLL (PLL1) disable. + */ +#if !defined(LPC17xx_USBCLKPLL0_SELECT) || defined(__DOXYGEN__) +#define LPC17xx_USBCLKPLL0_SELECT USBSEL_PLL0_DIV_6 +#endif +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/** + * @brief Calculated OSCRANGE setting. + */ +#if (MAINOSCCLK < 18000000) || defined(__DOXYGEN__) +#define LPC17xx_OSCRANGE 0 +#else +#define LPC17xx_OSCRANGE 1 +#endif + +/** + * @brief PLL input clock frequency. + */ +#if (LPC17xx_SYSCLK_SELECT == CLKSRCSEL_IRCOSC) || defined(__DOXYGEN__) +#define LPC17xx_SYSCLK IRCOSCCLK +#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_MAINOSC +#define LPC17xx_SYSCLK MAINOSCCLK +#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_RTCOSC +#define LPC17xx_SYSCLK RTCOSCCLK +#else +#error "Invalid LPC17xx_SYSCLK_SELECT clock source specified." +#endif + +/** + * @brief MSEL mask in SYSPLLCTRL register. + */ +#if ((LPC17xx_MAINPLL_MUL % 2) == 0) || defined(__DOXYGEN__) +#define LPC17xx_PLL0CFG_MSEL0 ((LPC17xx_MAINPLL_MUL/2) - 1) +#else +#error "Invalid LPC17xx_PLL0CFG_MUL value." +#endif + +/** + * @brief PSEL mask in SYSPLLCTRL register. + */ +#if ((LPC17xx_MAINPLL_PREDIV >= 1) && (LPC17xx_MAINPLL_PREDIV <= 32)) || defined(__DOXYGEN__) +#define LPC17xx_PLL0CFG_NSEL0 (LPC17xx_MAINPLL_PREDIV - 1) +#else +#error "Invalid LPC17xx_MAINPLL_PREDIV value (1 to 32 accepted)." +#endif + +/** + * @brief CCO frequency. + */ +#define LPC17xx_MAINPLLCCO ((LPC17xx_MAINPLL_MUL * \ + LPC17xx_SYSCLK)/LPC17xx_MAINPLL_PREDIV) + +#if (LPC17xx_MAINPLLCCO < 275000000) || (LPC17xx_SYSPLLCCO > 550000000) +#error "CCO frequency out of the acceptable range (275...550)." +#endif + +/** + * @brief PLL output clock frequency. + */ +#if LPC17xx_MAINPLL_ENABLE +#define LPC17xx_MAINPLLCLK LPC17xx_MAINPLLCCO +#else +#define LPC17xx_MAINPLLCLK LPC17xx_SYSCLK +#endif + +/** + * @brief CPU clock frequency. + * @note Most of LPC17xx have max 120 MHz clock. + */ +#define LPC17xx_CCLK (LPC17xx_MAINPLLCLK/LPC17xx_CCLK_DIV) +#if (LPC17xx_CCLK > 120000000) || defined(__DOXYGEN__) +#error "CPU Clock out of range." +#endif + +#if LPC17xx_USBPLL_ENABLE +/** + * @brief Main oscillator out of range. + */ +#if ((MAINOSCCLK < 10000000) && (MAINOSCCLK > 25000000)) || defined(__DOXYGEN__) +#error "Main oscillator clock out of range." +#endif + +/** + * @brief MSEL1 mask in PLL1CFG register. + */ +#if (LPC17xx_USBPLL_MUL >= 1) && (LPC17xx_USBPLL_MUL <= 32) || defined(__DOXYGEN__) +#define LPC17xx_PLL1CFG_MSEL1 (LPC17xx_USBPLL_MUL - 1) +#else +#error "Invalid LPC17xx_USBPLL_MUL value (1 to 32 accepted)." +#endif + +/** + * @brief PSEL1 mask in PLL1CFG register. + */ +#if (LPC17xx_USBPLL_DIV == 2) || defined(__DOXYGEN__) +#define LPC17xx_PLL1CFG_PSEL1 0UL +#elif (LPC17xx_USBPLL_DIV == 4) +#define LPC17xx_PLL1CFG_PSEL1 1UL +#elif (LPC17xx_USBPLL_DIV == 8) +#define LPC17xx_PLL1CFG_PSEL1 2UL +#elif (LPC17xx_USBPLL_DIV == 16) +#define LPC17xx_PLL1CFG_PSEL1 3UL +#else +#error "Invalid LPC17xx_USBPLL_DIV value (2, 4, 8, 16 accepted)." +#endif + +/** + * @brief USB PLL CCO frequency. + */ +#define LPC17xx_USBPLLCCO (MAINOSCCLK * LPC17xx_USBPLL_MUL * \ + LPC17xx_USBPLL_DIV) + +#if (LPC17xx_USBPLLCCO < 156000000) || (LPC17xx_SYSPLLCCO > 320000000) +#error "CCO frequency out of the acceptable range (156...320)" +#endif + +/** + * @brief USB clock frequency. + * @note Must be 48 MHz. + */ +#define LPC17xx_USBCLK (LPC17xx_USBPLLCCO/LPC17xx_USBPLL_DIV) +#if (LPC17xx_USBCLK != 48000000) || defined(__DOXYGEN__) +#error "USB clock out of range." +#endif +#endif + +/** + * @brief Peripheral clock frequency. + */ +#if (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_4) || defined(__DOXYGEN__) +#define LPC17xx_PCLK (LPC17xx_CCLK/4) +#define LPC17xx_PCLKSEL0 0x00 +#define LPC17xx_PCLKSEL1 0x00 +#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK) +#define LPC17xx_PCLK (LPC17xx_CCLK) +#define LPC17xx_PCLKSEL0 0x55515155 +#define LPC17xx_PCLKSEL1 0x54555455 +#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_2) +#define LPC17xx_PCLK (LPC17xx_CCLK/2) +#define LPC17xx_PCLKSEL0 0xAAA2A2AA +#define LPC17xx_PCLKSEL1 0xA8AAA8AA +#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_8) +#define LPC17xx_PCLK (LPC17xx_CCLK/8) +#define LPC17xx_PCLKSEL0 0xFFF3F3FF +#define LPC17xx_PCLKSEL1 0xFCFFFCFF +#else +#error "Invalid LPC17xx_PCLK_SELECT value" +#endif + +/** + * @brief LPC17xx_CLKOUT_DIV out of range. + */ +#if ((LPC17xx_CLKOUT_DIV < 1) && (LPC17xx_CLKOUT_DIV > 16)) || defined(__DOXYGEN__) +#error "Invalid LPC17xx_CLKOUT_DIV value (1 to 16 accepted)." +#endif + +/** + * @brief CLKOUT frequency. + */ +#if (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_CCLK) || defined(__DOXYGEN__) +#define LPC17xx_CLKOUTCLK (LPC17xx_CCLK/LPC17xx_CLKOUT_DIV) +#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_MAINOSC) +#define LPC17xx_CLKOUTCLK (MAINOSCCLK/LPC17xx_CLKOUT_DIV) +#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_IRCOSC) +#define LPC17xx_CLKOUTCLK (IRCOSCCLK/LPC17xx_CLKOUT_DIV) +#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_USBCLK) +#define LPC17xx_CLKOUTCLK (LPC17xx_USBCLK/LPC17xx_CLKOUT_DIV) +#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_RTCOSC) +#define LPC17xx_CLKOUTCLK (RTCOSCCLK/LPC17xx_CLKOUT_DIV) +#else +#error "Invalid LPC17xx_CLKOUT_SELECT value." +#endif + +/** + * @brief CLKOUT frequency out of range. + */ +#if (LPC17xx_CLKOUTCLK > 50000000) || defined(__DOXYGEN__) +#error "CLKOUT frequency out of the acceptable range (less than 50 MHz)" +#endif + +/** + * @brief Flash wait states. + */ +#if (LPC17xx_CCLK <= 20000000) || defined(__DOXYGEN__) +#define LPC17xx_FLASHCFG_FLASHTIM 0UL +#elif LPC17xx_CCLK <= 40000000 +#define LPC17xx_FLASHCFG_FLASHTIM 1UL +#elif LPC17xx_CCLK <= 60000000 +#define LPC17xx_FLASHCFG_FLASHTIM 2UL +#elif LPC17xx_CCLK <= 80000000 +#define LPC17xx_FLASHCFG_FLASHTIM 3UL +#elif LPC17xx_CCLK <= 120000000 +#define LPC17xx_FLASHCFG_FLASHTIM 4UL +#else +#define LPC17xx_FLASHCFG_FLASHTIM 5UL +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of the realtime free counter value. + */ +typedef uint32_t halrtcnt_t; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the current value of the system free running counter. + * @note This service is implemented by returning the content of the + * DWT_CYCCNT register. + * + * @return The value of the system free running counter of + * type halrtcnt_t. + * + * @notapi + */ +#define hal_lld_get_counter_value() DWT_CYCCNT + +/** + * @brief Realtime counter frequency. + * @note The DWT_CYCCNT register is incremented directly by the cpu + * clock so this function returns LPC17xx_CCLK. + * + * @return The realtime counter frequency of type halclock_t. + * + * @notapi + */ +#define hal_lld_get_counter_frequency() LPC17xx_CCLK + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#include "lpc17xx_dma.h" + +#ifdef __cplusplus +extern "C" { +#endif + void hal_lld_init(void); + void LPC17xx_clock_init(void); +#ifdef __cplusplus +} +#endif + +#endif /* _HAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/i2c_lld.c b/os/hal/platforms/LPC17xx/i2c_lld.c new file mode 100644 index 000000000..0fc0bda40 --- /dev/null +++ b/os/hal/platforms/LPC17xx/i2c_lld.c @@ -0,0 +1,533 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx I2C driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + + +/** + * @file LPC17xx/i2c_lld.h + * @brief LPC17xx I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if LPC17xx_I2C_USE_I2C0 || defined(__DOXYGEN__) +/** @brief I2C1 driver identifier.*/ +I2CDriver I2CD1; +#endif + +#if LPC17xx_I2C_USE_I2C1 || defined(__DOXYGEN__) +/** @brief I2C2 driver identifier.*/ +I2CDriver I2CD2; +#endif + +#if LPC17xx_I2C_USE_I2C2 || defined(__DOXYGEN__) +/** @brief I2C3 driver identifier.*/ +I2CDriver I2CD3; +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Wakes up the waiting thread. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] msg wakeup message + * + * @notapi + */ +#define wakeup_isr(i2cp, msg) { \ + chSysLockFromIsr(); \ + if ((i2cp)->thread != NULL) { \ + Thread *tp = (i2cp)->thread; \ + (i2cp)->thread = NULL; \ + tp->p_u.rdymsg = (msg); \ + chSchReadyI(tp); \ + } \ + chSysUnlockFromIsr(); \ +} + +/** + * @brief Handling of stalled I2C transactions. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_safety_timeout(void *p) { + I2CDriver *i2cp = (I2CDriver *)p; + + chSysLockFromIsr(); + if (i2cp->thread) { + Thread *tp = i2cp->thread; + i2cp->thread = NULL; + tp->p_u.rdymsg = RDY_TIMEOUT; + chSchReadyI(tp); + } + chSysUnlockFromIsr(); +} + +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t status) { + i2cflags_t error = 0; + + switch (status) { + case I2C_STATE_ARB_LOST: + error = I2CD_ARBITRATION_LOST; + break; + case I2C_STATE_BUS_ERROR: + error = I2CD_BUS_ERROR; + break; + case I2C_STATE_MS_SLAR_NACK: + case I2C_STATE_MS_TDAT_NACK: + case I2C_STATE_MS_SLAW_NACK: + error = I2CD_ACK_FAILURE ; + break; + } + + /* If some error has been identified then sends wakes the waiting thread.*/ + i2cp->errors = error; + wakeup_isr(i2cp, RDY_RESET); +} + +/** + * @brief I2C serve interrupt handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_interrupt(I2CDriver *i2cp) { + uint32_t status; + LPC_I2C_TypeDef *dp = i2cp->i2c; + + status = dp->STAT; + switch(status) { + case I2C_STATE_MS_START: /* A START condition has been transmitted. */ + if (i2cp->txbytes > 0) { + dp->DAT = i2cp->addr; /* Write slave address with WR bit. */ + } + else { + dp->DAT = i2cp->addr | I2C_RD_BIT; /* Write slave address with RD bit. */ + } + + dp->CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC; /* Clear START and SI bit. */ + break; + + case I2C_STATE_MS_SLAR_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + case I2C_STATE_MS_TDAT_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + case I2C_STATE_MS_SLAW_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + dp->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + dp->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + i2c_lld_serve_error_interrupt(i2cp, status); + break; + + case I2C_STATE_MS_SLAW_ACK: /* SLA + W has been transmitted, ACK has been received. */ + case I2C_STATE_MS_TDAT_ACK: /* Data byte has been transmitted, ACK has been received. */ + if (i2cp->txbytes > 0) { + dp->DAT = *i2cp->txbuf++; /* Write data. */ + i2cp->txbytes--; + } + else { + if (i2cp->rxbytes > 0) { + dp->CONSET = I2C_CONSET_STO | I2C_CONSET_STA; /* Set START and STOP bit. */ + } /* STOP bit will be transmit, then START bit. */ + else { + dp->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + wakeup_isr(i2cp, RDY_OK); + } + } + dp->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + break; + + case I2C_STATE_MS_SLAR_ACK: /* SLA + R has been transmitted, ACK has been received. */ + case I2C_STATE_MS_RDAT_ACK: /* Data byte has been received, ACK has been returned. */ + if (status == I2C_STATE_MS_RDAT_ACK) { + *i2cp->rxbuf++ = dp->DAT; /* Read data */ + i2cp->rxbytes--; + } + if (i2cp->rxbytes == 1) { + dp->CONCLR = I2C_CONCLR_SIC | I2C_CONCLR_AAC; /* Clear SI and ACK bit. */ + } + else { + dp->CONSET = I2C_CONSET_AA; /* Set ACK bit. */ + dp->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + } + break; + + case I2C_STATE_MS_RDAT_NACK: /* Data byte has been received, NOT ACK has been returned. */ + *i2cp->rxbuf++ = dp->DAT; /* Read data. */ + i2cp->rxbytes--; + dp->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + dp->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + wakeup_isr(i2cp, RDY_OK); + break; + + case I2C_STATE_BUS_ERROR: /* Bus error. */ + case I2C_STATE_ARB_LOST: /* Arbitration lost. */ + dp->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + i2c_lld_serve_error_interrupt(i2cp, status); + break; + } + +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ +#if LPC17xx_I2C_USE_I2C0 || defined(__DOXYGEN__) +/** + * @brief I2C0 event interrupt handler. + * + * @notapi + */ +CH_IRQ_HANDLER(Vector68) { + + CH_IRQ_PROLOGUE(); + i2c_lld_serve_interrupt(&I2CD1); + CH_IRQ_EPILOGUE(); +} +#endif + +#if LPC17xx_I2C_USE_I2C1 || defined(__DOXYGEN__) +/** + * @brief I2C1 event interrupt handler. + * + * @notapi + */ +CH_IRQ_HANDLER(Vector6C) { + + CH_IRQ_PROLOGUE(); + i2c_lld_serve_interrupt(&I2CD2); + CH_IRQ_EPILOGUE(); +} +#endif + +#if LPC17xx_I2C_USE_I2C2 || defined(__DOXYGEN__) +/** + * @brief I2C2 event interrupt handler. + * + * @notapi + */ +CH_IRQ_HANDLER(Vector70) { + + CH_IRQ_PROLOGUE(); + i2c_lld_serve_interrupt(&I2CD3); + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if LPC17xx_I2C_USE_I2C0 + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = LPC_I2C0; +#endif + +#if LPC17xx_I2C_USE_I2C1 + i2cObjectInit(&I2CD2); + I2CD2.thread = NULL; + I2CD2.i2c = LPC_I2C1; +#endif + +#if LPC17xx_I2C_USE_I2C2 + i2cObjectInit(&I2CD3); + I2CD3.thread = NULL; + I2CD3.i2c = LPC_I2C2; +#endif +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + + uint32_t i2cscl; + uint32_t mulh, mull, div; + LPC_I2C_TypeDef *dp = i2cp->i2c; + + /* If in stopped state then enables the I2C clock. */ + if (i2cp->state == I2C_STOP) { +#if LPC17xx_I2C_USE_I2C0 + if (&I2CD1 == i2cp) { + LPC_SC->PCONP |= (1UL << 7); + nvicEnableVector(I2C0_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_I2C_I2C0_IRQ_PRIORITY)); + } +#endif + +#if LPC17xx_I2C_USE_I2C1 + if (&I2CD2 == i2cp) { + LPC_SC->PCONP |= (1UL << 19); + nvicEnableVector(I2C1_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_I2C_I2C1_IRQ_PRIORITY)); + } +#endif + +#if LPC17xx_I2C_USE_I2C2 + if (&I2CD3 == i2cp) { + LPC_SC->PCONP |= (1UL << 26); + nvicEnableVector(I2C2_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_I2C_I2C2_IRQ_PRIORITY)); + } +#endif + } + + /* Make sure I2C peripheral is disabled */ + dp->CONCLR = I2C_CONCLR_ENC; + + /* Setup I2C clock parameters.*/ + i2cscl = (LPC17xx_PCLK/(i2cp->config->clock_timing)); + if (i2cp->config->mode == I2C_FAST_MODE) { + div = 19; + mull = 13; + mulh = 6; + } else if (i2cp->config->mode == I2C_FAST_MODE_PLUS) { + div = 3; + mull = 2; + mulh = 1; + } else { /* i2cp->config->mode == I2C_STANDARD_MODE */ + div = 2; + mull = 1; + mulh = 1; + } + + dp->SCLH = (mulh * i2cscl) / div; + dp->SCLL = (mull * i2cscl) / div; + + /* Enable I2C.*/ + dp->CONSET |= I2C_CONSET_EN; + +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* I2C disable.*/ + i2cp->i2c->CONCLR = I2C_CONCLR_ENC; +#if LPC17xx_I2C_USE_I2C0 + if (&I2CD1 == i2cp) { + nvicDisableVector(I2C0_IRQn); + LPC_SC->PCONP &= ~(1UL << 7); + } +#endif + +#if LPC17xx_I2C_USE_I2C1 + if (&I2CD2 == i2cp) { + nvicDisableVector(I2C1_IRQn); + LPC_SC->PCONP &= ~(1UL << 19); + } +#endif + +#if LPC17xx_I2C_USE_I2C2 + if (&I2CD3 == i2cp) { + nvicDisableVector(I2C2_IRQn); + LPC_SC->PCONP &= ~(1UL << 26); + } +#endif + } +} + +/** + * @brief Receives data via the I2C bus as master. + * @details Number of receiving bytes must be more than 1 on STM32F1x. This is + * hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval RDY_OK if the function succeeded. + * @retval RDY_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state</b>. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + LPC_I2C_TypeDef *dp = i2cp->i2c; + VirtualTimer vt; + + i2cp->addr = addr << 1; + /* Global timeout for the whole operation.*/ + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + + /* Releases the lock from high level driver.*/ + chSysUnlock(); + + /* Initializes driver fields */ + i2cp->errors = 0; + i2cp->rxbuf = rxbuf; + i2cp->rxbytes = rxbytes; + + /* This lock will be released in high level driver.*/ + chSysLock(); + + /* Atomic check on the timer in order to make sure that a timeout didn't + happen outside the critical zone.*/ + if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + return RDY_TIMEOUT; + + /* Starts the operation.*/ + dp->CONSET = I2C_CONSET_STA; + + /* Waits for the operation completion or a timeout.*/ + i2cp->thread = chThdSelf(); + chSchGoSleepS(THD_STATE_SUSPENDED); + if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) + chVTResetI(&vt); + + return chThdSelf()->p_u.rdymsg; +} + +/** + * @brief Transmits data via the I2C bus as master. + * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. + * This is hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval RDY_OK if the function succeeded. + * @retval RDY_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state</b>. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + LPC_I2C_TypeDef *dp = i2cp->i2c; + VirtualTimer vt; + + i2cp->addr = addr << 1; + /* Global timeout for the whole operation.*/ + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + + /* Releases the lock from high level driver.*/ + chSysUnlock(); + + /* Initializes driver fields */ + i2cp->errors = 0; + i2cp->txbuf = txbuf; + i2cp->txbytes = txbytes; + i2cp->rxbuf = rxbuf; + i2cp->rxbytes = rxbytes; + + /* This lock will be released in high level driver.*/ + chSysLock(); + + /* Atomic check on the timer in order to make sure that a timeout didn't + happen outside the critical zone.*/ + if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + return RDY_TIMEOUT; + + /* Starts the operation.*/ + dp->CONSET = I2C_CONSET_STA; + + /* Waits for the operation completion or a timeout.*/ + i2cp->thread = chThdSelf(); + chSchGoSleepS(THD_STATE_SUSPENDED); + + if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) + chVTResetI(&vt); + + return chThdSelf()->p_u.rdymsg; +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/i2c_lld.h b/os/hal/platforms/LPC17xx/i2c_lld.h new file mode 100644 index 000000000..2cf15b50e --- /dev/null +++ b/os/hal/platforms/LPC17xx/i2c_lld.h @@ -0,0 +1,271 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx I2C driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC17xx/i2c_lld.h + * @brief LPC17xx I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef _I2C_LLD_H_ +#define _I2C_LLD_H_ + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define I2C_CONSET_AA 0x04 /* Assert acknowledge flag. */ +#define I2C_CONSET_SI 0x08 /* I2C interrupt flag. */ +#define I2C_CONSET_STO 0x10 /* STOP flag. */ +#define I2C_CONSET_STA 0x20 /* START flag. */ +#define I2C_CONSET_EN 0x40 /* I2C interface enable. */ + +#define I2C_CONCLR_AAC 0x04 /* Assert acknowledge Clear bit. */ +#define I2C_CONCLR_SIC 0x08 /* I2C interrupt Clear bit. */ +#define I2C_CONCLR_STAC 0x20 /* START flag Clear bit. */ +#define I2C_CONCLR_ENC 0x40 /* I2C interface Disable bit. */ + +#define I2C_WR_BIT 0x00 +#define I2C_RD_BIT 0x01 + +#define I2C_STATE_MS_START 0x08 +#define I2C_STATE_MS_RSTART 0x10 +#define I2C_STATE_MS_SLAW_ACK 0x18 +#define I2C_STATE_MS_SLAW_NACK 0x20 +#define I2C_STATE_MS_TDAT_ACK 0x28 +#define I2C_STATE_MS_TDAT_NACK 0x30 +#define I2C_STATE_ARB_LOST 0x38 + +#define I2C_STATE_MS_SLAR_ACK 0x40 +#define I2C_STATE_MS_SLAR_NACK 0x48 +#define I2C_STATE_MS_RDAT_ACK 0x50 +#define I2C_STATE_MS_RDAT_NACK 0x58 + +#define I2C_STATE_BUS_ERROR 0x00 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C0 driver enable switch. + * @details If set to @p TRUE the support for device I2C0 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC17xx_I2C_USE_I2C0) || defined(__DOXYGEN__) +#define LPC17xx_I2C_USE_I2C0 FALSE +#endif + +/** + * @brief I2C0 interrupt priority level setting. + */ +#if !defined(LPC17xx_I2C_I2C0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_I2C_I2C0_IRQ_PRIORITY 3 +#endif + +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for device I2C0 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC17xx_I2C_USE_I2C1) || defined(__DOXYGEN__) +#define LPC17xx_I2C_USE_I2C1 FALSE +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(LPC17xx_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_I2C_I2C1_IRQ_PRIORITY 3 +#endif + +/** + * @brief I2C2 driver enable switch. + * @details If set to @p TRUE the support for device I2C0 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC17xx_I2C_USE_I2C2) || defined(__DOXYGEN__) +#define LPC17xx_I2C_USE_I2C2 FALSE +#endif + +/** + * @brief I2C0 interrupt priority level setting. + */ +#if !defined(LPC17xx_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_I2C_I2C2_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief I2C Driver condition flags type. + */ +typedef uint32_t i2cflags_t; +/** + * @brief Supported modes for the I2C bus. + */ +typedef enum { + I2C_STANDARD_MODE = 1, + I2C_FAST_MODE = 2, + I2C_FAST_MODE_PLUS = 3, +} i2cmode_t; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + i2cmode_t mode; /**< @brief Specifies the I2C mode. */ + uint32_t clock_timing; /**< @brief Specifies the clock timing */ +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + Mutex mutex; +#elif CH_USE_SEMAPHORES + Semaphore semaphore; +#endif +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + Thread *thread; + /** + * @brief Current slave address without R/W bit. + */ + i2caddr_t addr; + /** + * @brief Pointer to the transmit buffer. + */ + const uint8_t *txbuf; + /** + * @brief Number of bytes to transmit. + */ + size_t txbytes; + /** + * @brief Pointer to the receive buffer. + */ + uint8_t *rxbuf; + /** + * @brief Number of bytes to receive. + */ + size_t rxbytes; + /** + * @brief Pointer to the I2C registers block. + */ + LPC_I2C_TypeDef *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC17xx_I2C_USE_I2C0 && !defined(__DOXYGEN__) +extern I2CDriver I2CD1; +#endif + +#if LPC17xx_I2C_USE_I2C1 && !defined(__DOXYGEN__) +extern I2CDriver I2CD2; +#endif + +#if LPC17xx_I2C_USE_I2C2 && !defined(__DOXYGEN__) +extern I2CDriver I2CD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); +#ifdef __cplusplus +} +#endif +#endif +#endif /* _I2C_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/lpc17xx_dma.c b/os/hal/platforms/LPC17xx/lpc17xx_dma.c new file mode 100644 index 000000000..b4ae57d31 --- /dev/null +++ b/os/hal/platforms/LPC17xx/lpc17xx_dma.c @@ -0,0 +1,205 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/LPC17xx_dma.c + * @brief DMA driver code. + * + * @addtogroup LPC17xx_DMA + * @details DMA sharing helper driver. In the LPC17xx the DMA streams are a + * shared resource, this driver allows to allocate and free DMA + * streams at runtime in order to allow all the other device + * drivers to coordinate the access to the resource. + * @note The DMA ISR handlers are all declared into this module because + * sharing, the various device drivers can associate a callback to + * ISRs when allocating streams. + * @{ + */ + +#include "ch.h" +#include "hal.h" + +/* The following macro is only defined if some driver requiring DMA services + has been enabled.*/ +#if defined(LPC17xx_DMA_REQUIRED) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + + LPC_GPDMACH_TypeDef * \ + _lpc17xx_dma_channel_config_t[LPC17xx_DMA_CHANNELS] = { + LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4, + LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7 }; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief DMA ISR redirector type. + */ +typedef struct { + lpc17xx_dmaisr_t dma_func; /**< @brief DMA callback function. */ + void *dma_param; /**< @brief DMA callback parameter. */ +} dma_isr_redir_t; + +/** + * @brief Mask of the allocated streams. + */ +static uint32_t dma_streams_mask; + +/** + * @brief DMA IRQ redirectors. + */ +static dma_isr_redir_t dma_isr_redir[LPC17xx_DMA_CHANNELS]; + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief DMA interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(VectorA8) { + uint32_t irq_status; + uint32_t err_status; + uint8_t i; + + CH_IRQ_PROLOGUE(); + + irq_status = LPC_GPDMA->IntTCStat; + LPC_GPDMA->IntTCClear = irq_status; /* Clear DMA interrupt flag */ + err_status = LPC_GPDMA->IntErrStat; + LPC_GPDMA->IntErrClr = err_status; /* Clear DMA error flag if any*/ + + for (i = 0; i < LPC17xx_DMA_CHANNELS; i++) { + if (irq_status & (1UL << i)) { + if (dma_isr_redir[i].dma_func) + dma_isr_redir[i].dma_func(dma_isr_redir[i].dma_param, err_status); + } + } + + + CH_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief LPC17xx DMA initialization. + * + * @init + */ +void dmaInit(void) { + uint8_t i; + + LPC_SC->PCONP |= (1UL << 29); /* Enable DMA power */ + + /* Disable all channels */ + for (i = 0; i < LPC17xx_DMA_CHANNELS; i++) + _lpc17xx_dma_channel_config_t[i]->CConfig = 0; + + LPC_GPDMA->IntTCClear = 0xFF; + LPC_GPDMA->IntErrClr = 0xFF; + + LPC_GPDMA->Config = DMACCONFIG_E; /* Enable DMA Controller */ + while((LPC_GPDMA->Config & DMACCONFIG_E) != 0x01) + ; + + nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_DMA_IRQ_PRIORITY)); +} + +/** + * @brief Allocates a DMA channel. + * @details The channel is allocated. + * @pre The channel must not be already in use or an error is returned. + * @post The channel is allocated and the default ISR handler redirected + * to the specified function. + * @post The channel must be freed using @p dmaChannelRelease() before it can + * be reused with another peripheral. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmach DMA channel number + * @param[in] func handling function pointer, can be @p NULL + * @param[in] param a parameter to be passed to the handling function + * @return The operation status. + * @retval FALSE no error, stream taken. + * @retval TRUE error, stream already taken. + * + * @special + */ +bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach, + lpc17xx_dmaisr_t func, + void *param) { + uint32_t channel; + channel = (1UL << dmach); + + /* Checks if the channel is already taken.*/ + if ((dma_streams_mask & channel) != 0) + return TRUE; + + /* Marks the stream as allocated.*/ + dma_isr_redir[dmach].dma_func = func; + dma_isr_redir[dmach].dma_param = param; + dma_streams_mask |= channel; + + return FALSE; +} + +/** + * @brief Releases a DMA channel. + * @details The channel is freed. + * Trying to release a unallocated channel is an illegal operation + * and is trapped if assertions are enabled. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post The channel is again available. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmach DMA channel number + * + * @special + */ +void dmaChannelRelease(lpc17xx_dma_channel_t dmach) { + + uint32_t channel; + channel = (1UL << dmach); + + /* Check if the streams is not taken.*/ + chDbgAssert((dma_streams_mask & channel) != 0, + "dmaStreamRelease(), #1", "not allocated"); + + dma_streams_mask &= ~channel; /* Marks the stream as not allocated.*/ +} + +#endif /* LPC17xx_DMA_REQUIRED */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/lpc17xx_dma.h b/os/hal/platforms/LPC17xx/lpc17xx_dma.h new file mode 100644 index 000000000..e581265a5 --- /dev/null +++ b/os/hal/platforms/LPC17xx/lpc17xx_dma.h @@ -0,0 +1,415 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/LPC17xx_dma.h + * @brief DMA driver header. + * + * @addtogroup LPC17xx_DMA + * @{ + */ + +#ifndef _LPC17xx_DMA_H_ +#define _LPC17xx_DMA_H_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define DMACCONFIG_E (1UL << 0) +#define DMACCONFIG_M (1UL << 1) + +/** + * @brief Total number of DMA streams. + * @note This is the total number of streams among all the DMA units. + */ +#define LPC17xx_DMA_CHANNELS 8 + +/** + * @name DMA control data configuration + * @{ + */ + +/** + * @brief DMA transfer size. + * + * @param[in] n DMA transfer size + */ +#define DMA_CTRL_TRANSFER_SIZE(n) (n) + +/** + * @brief DMA source burst size. + */ +#define DMA_CTRL_SRC_BSIZE_1 (0 << 12) +#define DMA_CTRL_SRC_BSIZE_4 (1UL << 12) +#define DMA_CTRL_SRC_BSIZE_8 (2UL << 12) +#define DMA_CTRL_SRC_BSIZE_16 (3UL << 12) +#define DMA_CTRL_SRC_BSIZE_32 (4UL << 12) +#define DMA_CTRL_SRC_BSIZE_64 (5UL << 12) +#define DMA_CTRL_SRC_BSIZE_128 (6UL << 12) +#define DMA_CTRL_SRC_BSIZE_256 (7UL << 12) + +/** + * @brief DMA destination burst size. + * @{ + */ +#define DMA_CTRL_DST_BSIZE_1 (0 << 15) +#define DMA_CTRL_DST_BSIZE_4 (1UL << 15) +#define DMA_CTRL_DST_BSIZE_8 (2UL << 15) +#define DMA_CTRL_DST_BSIZE_16 (3UL << 15) +#define DMA_CTRL_DST_BSIZE_32 (4UL << 15) +#define DMA_CTRL_DST_BSIZE_64 (5UL << 15) +#define DMA_CTRL_DST_BSIZE_128 (6UL << 15) +#define DMA_CTRL_DST_BSIZE_256 (7UL << 15) +/** @} */ + +/** + * @name DMA source transfer width. + * @{ + */ +#define DMA_CTRL_SRC_WIDTH_BYTE (0 << 18) +#define DMA_CTRL_SRC_WIDTH_HWORD (1UL << 18) +#define DMA_CTRL_SRC_WIDTH_WORD (2UL << 18) +/** @} */ + +/** + * @name DMA destination transfer width. + * @{ + */ +#define DMA_CTRL_DST_WIDTH_BYTE (0 << 21) +#define DMA_CTRL_DST_WIDTH_HWORD (1UL << 21) +#define DMA_CTRL_DST_WIDTH_WORD (2UL << 21) + +/** + * @name DMA source increment after each transfer. + * @{ + */ +#define DMA_CTRL_SRC_NOINC (0UL << 26) +#define DMA_CTRL_SRC_INC (1UL << 26) + +/** + * @name DMA destination increment after each transfer. + * @{ + */ +#define DMA_CTRL_DST_NOINC (0UL << 27) +#define DMA_CTRL_DST_INC (1UL << 27) + +/** + * @name DMA bus access bits. + * @{ + */ +#define DMA_CTRL_PROT1_USER (0 << 28) +#define DMA_CTRL_PROT1_PRIV (1UL << 28) + +#define DMA_CTRL_PROT2_NONBUFF (0 << 29) +#define DMA_CTRL_PROT2_BUFF (1UL << 29) + +#define DMA_CTRL_PROT3_NONCACHE (0 << 30) +#define DMA_CTRL_PROT3_CACHE (1UL << 30) +/** @} */ + +/** + * @name DMA terminal count interrupt enable. + * @{ + */ +#define DMA_CTRL_INT (1UL << 31) +/** @} */ + +/** + * @name DMA channel enable. + * @{ + */ +#define DMA_CFG_CH_ENABLE (1UL << 0) + +/** + * @brief Source peripheral. + * + * @param[in] source source peripheral + */ +#define DMA_CFG_SRC_PERIPH(src) ((src) << 1) + +/** + * @brief Destination peripheral. + * + * @param[in] destination destination peripheral + */ +#define DMA_CFG_DST_PERIPH(dst) ((dst) << 6) + +/** + * @name Transfer type. + * @{ + */ +#define DMA_CFG_TTYPE_M2M (0 << 11) +#define DMA_CFG_TTYPE_M2P (1UL << 11) +#define DMA_CFG_TTYPE_P2M (2UL << 11) +#define DMA_CFG_TTYPE_P2P (3UL << 11) +/** @} */ + +/** + * @name Interrupt error mask. + * @{ + */ +#define DMA_CFG_IE (1UL << 14) +/** @} */ + +/** + * @name Terminal count interrupt mask. + * @{ + */ +#define DMA_CFG_ITC (1UL << 15) +/** @} */ + +/** + * @name Active. + * @note Read only + * @{ + */ +#define DMA_CFG_ACTIVE (1UL << 17) +/** @} */ + +/** + * @name Halt. + * @{ + */ +#define DMA_CFG_HALT (1UL << 18) +/** @} */ +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief DMA interrupt priority level setting. + */ +#if !defined(LPC17xx_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_DMA_IRQ_PRIORITY 3 +#endif + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +typedef struct { + volatile uint32_t srcaddr; /**< @brief Source address. */ + volatile uint32_t dstaddr; /**< @brief Destination address. */ + volatile uint32_t lli; /**< @brief Linked List Item. */ + volatile uint32_t control; /**< @brief Control. */ + volatile uint32_t config; /**< @brief Configuration. */ +} lpc17xx_dma_channel_config_t; + +/** + * @brief DMA channel number. + */ +typedef enum { + DMA_CHANNEL0 = 0, + DMA_CHANNEL1 = 1, + DMA_CHANNEL2 = 2, + DMA_CHANNEL3 = 3, + DMA_CHANNEL4 = 4, + DMA_CHANNEL5 = 5, + DMA_CHANNEL6 = 6, + DMA_CHANNEL7 = 7 + +} lpc17xx_dma_channel_t; + + /** + * @brief DMA source or destination type. + */ + typedef enum { + DMA_SSP0_TX = 0, + DMA_SSP0_RX = 1, + DMA_SSP1_TX = 2, + DMA_SSP1_RX = 3, + DMA_ADC = 4, + DMA_I2S_CH0 = 5, + DMA_I2S_CH1 = 6, + DMA_DAC = 7, + DMA_UART0_TX_MAT0_0 = 8, + DMA_UART0_RX_MAT0_1 = 9, + DMA_UART1_TX_MAT1_0 = 10, + DMA_UART1_RX_MAT1_1 = 11, + DMA_UART2_TX_MAT2_0 = 12, + DMA_UART2_RX_MAT2_1 = 13, + DMA_UART3_TX_MAT3_0 = 14, + DMA_UART3_RX_MAT3_1 = 15 + } lpc17xx_dma_src_dst_t; + +/** + * @brief LPC17xx DMA ISR function type. + * + * @param[in] p parameter for the registered function + * @param[in] flags pre-shifted content of the xISR register, the bits + * are aligned to bit zero + */ +typedef void (*lpc17xx_dmaisr_t)(void *p, uint32_t flags); + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ + +/** + * @brief Associates a memory source to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * @param[in] addr pointer to a source address + * + * @special + */ +#define dmaChannelSrcAddr(dmach, addr) \ + _lpc17xx_dma_channel_config_t[dmach]->CSrcAddr = (uint32_t)(addr) + +/** + * @brief Associates a memory destination to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * @param[in] addr pointer to a destination address + * + * @special + */ +#define dmaChannelDstAddr(dmach, addr) \ + _lpc17xx_dma_channel_config_t[dmach]->CDestAddr = (uint32_t)(addr) + +/** + * @brief Associates a linked list item address to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * @param[in] addr pointer to a linked list item + * + * @special + */ +#define dmaChannelLinkedList(dmach, addr) \ + _lpc17xx_dma_channel_config_t[dmach]->CLLI = (((uint32_t)(addr)) << 2) + +/** + * @brief Set control configuration to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * @param[in] ctrl control configuration value + * + * @special + */ +#define dmaChannelControl(dmach, ctrl) \ + _lpc17xx_dma_channel_config_t[dmach]->CControl = (ctrl) + +/** + * @brief Set configuration to a DMA channel. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaStreamAllocate(). + * @post After use the channel can be released using @p dmaStreamRelease(). + * + * @param[in] dmach DMA channel number + * @param[in] config dma channel configuration value + * + * @special + */ +#define dmaChannelConfig(dmach, config) \ + _lpc17xx_dma_channel_config_t[dmach]->CConfig = (config) + +/** + * @brief Trigger DMA software burst transfer request. + * + * @param[in] src peripheral source request + * + * @special + */ +#define dmaSoftBurstRequest(src) \ + LPC_GPDMA->SoftBReq = (src) + +/** + * @brief Trigger DMA software single transfer request. + * + * @param[in] src peripheral source request + * + * @special + */ +#define dmaSoftSingleRequest(src) \ + LPC_GPDMA->SoftSReq = (src) + +/** + * @brief DMA channel enable. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * + * @special + */ +#define dmaChannelEnable(dmach) \ + _lpc17xx_dma_channel_config_t[dmach]->CConfig |= (DMA_CFG_CH_ENABLE) + +/** + * @brief DMA channel disable. + * @note This function can be invoked in both ISR or thread context. + * @pre The channel must have been allocated using @p dmaChannelAllocate(). + * @post After use the channel can be released using @p dmaChannelRelease(). + * + * @param[in] dmach DMA channel number + * + * @special + */ +#define dmaChannelDisable(dmach) \ + _lpc17xx_dma_channel_config_t[dmach]->CConfig &= ~(DMA_CFG_CH_ENABLE) + +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern LPC_GPDMACH_TypeDef * _lpc17xx_dma_channel_config_t[]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void dmaInit(void); + bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach, + lpc17xx_dmaisr_t func, + void *param); + void dmaChannelRelease(lpc17xx_dma_channel_t dmach); +#ifdef __cplusplus +} +#endif + +#endif /* _LPC17xx_DMA_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/pal_lld.c b/os/hal/platforms/LPC17xx/pal_lld.c new file mode 100644 index 000000000..19aa390f8 --- /dev/null +++ b/os/hal/platforms/LPC17xx/pal_lld.c @@ -0,0 +1,158 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/pal_lld.c + * @brief LPC17xx GPIO low level driver code. + * + * @addtogroup PAL + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ +/** + * @brief LPC17xx I/O ports configuration. + * @details GPIO unit registers initialization. + * + * @param[in] config the LPC17xx ports configuration + * + * @notapi + */ +void _pal_lld_init(const PALConfig *config) { + + LPC_GPIO0->FIODIR = config->P0.dir; + LPC_GPIO1->FIODIR = config->P1.dir; + LPC_GPIO2->FIODIR = config->P2.dir; + LPC_GPIO3->FIODIR = config->P3.dir; + LPC_GPIO4->FIODIR = config->P4.dir; + LPC_GPIO0->FIOMASK = 0; + LPC_GPIO1->FIOMASK = 0; + LPC_GPIO2->FIOMASK = 0; + LPC_GPIO3->FIOMASK = 0; + LPC_GPIO4->FIOMASK = 0; + LPC_GPIO0->FIOPIN = config->P0.data; + LPC_GPIO1->FIOPIN = config->P1.data; + LPC_GPIO2->FIOPIN = config->P2.data; + LPC_GPIO3->FIOPIN = config->P3.data; + LPC_GPIO4->FIOPIN = config->P4.data; +} + +/** + * @brief Reads a group of bits. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @return The group logical states. + * + * @notapi + */ +uint32_t _pal_lld_readgroup(ioportid_t port, + ioportmask_t mask, + uint32_t offset) { + + uint32_t p; + + port->FIOMASK = ~((mask) << offset); + p = port->FIOPIN; + port->FIOMASK = 0; + return p; +} + +/** + * @brief Writes a group of bits. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group width + * are masked. + * + * @notapi + */ +void _pal_lld_writegroup(ioportid_t port, + ioportmask_t mask, + uint32_t offset, + uint32_t bits) { + + port->FIOMASK = ~((mask) << offset); + port->FIOPIN = bits; + port->FIOMASK = 0; +} +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with + * high state. + * @note This function does not alter the @p PINSELx registers. Alternate + * functions setup must be handled by device-specific code. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + + switch (mode) { + case PAL_MODE_RESET: + case PAL_MODE_INPUT: + port->FIODIR &= ~mask; + break; + case PAL_MODE_UNCONNECTED: + palSetPort(port, PAL_WHOLE_PORT); + case PAL_MODE_OUTPUT_PUSHPULL: + port->FIODIR |= mask; + break; + } +} + +#endif /* HAL_USE_PAL */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/pal_lld.h b/os/hal/platforms/LPC17xx/pal_lld.h new file mode 100644 index 000000000..45812b3f5 --- /dev/null +++ b/os/hal/platforms/LPC17xx/pal_lld.h @@ -0,0 +1,332 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/pal_lld.h + * @brief LPC17xx GPIO low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef _PAL_LLD_H_ +#define _PAL_LLD_H_ + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +#undef PAL_MODE_INPUT_PULLUP +#undef PAL_MODE_INPUT_PULLDOWN +#undef PAL_MODE_INPUT_ANALOG +#undef PAL_MODE_OUTPUT_OPENDRAIN + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @brief GPIO port setup info. + */ +typedef struct { + /** Initial value for FIO_PIN register.*/ + uint32_t data; + /** Initial value for FIO_DIR register.*/ + uint32_t dir; +} lpc17xx_gpio_setup_t; + +/** + * @brief GPIO static initializer. + * @details An instance of this structure must be passed to @p palInit() at + * system startup time in order to initialized the digital I/O + * subsystem. This represents only the initial setup, specific pads + * or whole ports can be reprogrammed at later time. + * @note The @p IOCON block is not configured, initially all pins have + * enabled pullups and are programmed as GPIO. It is responsibility + * of the various drivers to reprogram the pins in the proper mode. + * Pins that are not handled by any driver may be programmed in + * @p board.c. + */ +typedef struct { + /** @brief GPIO 0 setup data.*/ + lpc17xx_gpio_setup_t P0; + /** @brief GPIO 1 setup data.*/ + lpc17xx_gpio_setup_t P1; + /** @brief GPIO 2 setup data.*/ + lpc17xx_gpio_setup_t P2; + /** @brief GPIO 3 setup data.*/ + lpc17xx_gpio_setup_t P3; + /** @brief GPIO 4 setup data.*/ + lpc17xx_gpio_setup_t P4; +} PALConfig; + +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 32 + +/** + * @brief Whole port mask. + * @brief This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF) + +/** + * @brief Digital I/O port sized unsigned type. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Digital I/O modes. + */ +typedef uint32_t iomode_t; + +/** + * @brief Port Identifier. + */ +typedef LPC_GPIO_TypeDef *ioportid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/*===========================================================================*/ + +/** + * @brief GPIO0 port identifier. + */ +#define IOPORT1 LPC_GPIO0 +#define GPIO0 LPC_GPIO0 + +/** + * @brief GPIO1 port identifier. + */ +#define IOPORT2 LPC_GPIO1 +#define GPIO1 LPC_GPIO1 + +/** + * @brief GPIO2 port identifier. + */ +#define IOPORT3 LPC_GPIO2 +#define GPIO2 LPC_GPIO2 + +/** + * @brief GPIO3 port identifier. + */ +#define IOPORT4 LPC_GPIO3 +#define GPIO3 LPC_GPIO3 + +/** + * @brief GPIO3 port identifier. + */ +#define IOPORT5 LPC_GPIO4 +#define GPIO4 LPC_GPIO4 + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief Low level PAL subsystem initialization. + * + * @param[in] config architecture-dependent ports configuration + * + * @notapi + */ +#define pal_lld_init(config) _pal_lld_init(config) + +/** + * @brief Reads the physical I/O port states. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((port)->FIOPIN) + +/** + * @brief Reads the output latch. + * @details The purpose of this function is to read back the latched output + * value. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((port)->FIOPIN) + +/** + * @brief Writes a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->FIOPIN = (bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->FIOSET = bits) + +/** + * @brief Clears a bits mask on a I/O port. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->FIOCLR = bits) + +/** + * @brief Reads a group of bits. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @return The group logical states. + * + * @notapi + */ +#define pal_lld_readgroup(port, mask, offset) \ + _pal_lld_readgroup(port, mask, offset) + +/** + * @brief Writes a group of bits. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group width + * are masked. + * + * @notapi + */ +#define pal_lld_writegroup(port, mask, offset, bits) \ + _pal_lld_writegroup(port, mask, offset, bits) + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Writes a logical state on an output pad. + * @note This function is not meant to be invoked directly by the + * application code. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) \ + ((bit) == PAL_LOW) ? pal_lld_clearpad(port, pad) : \ + pal_lld_setpad(port, pad) + +/** + * @brief Sets a pad logical state to @p PAL_HIGH. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_setpad(port, pad) \ + ((port)->FIOSET = 1UL << (pad)) + +/** + * @brief Clears a pad logical state to @p PAL_LOW. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_clearpad(port, pad) \ + ((port)->FIOCLR = 1UL << (pad)) + +#if !defined(__DOXYGEN__) +extern const PALConfig pal_default_config; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const PALConfig *config); + uint32_t _pal_lld_readgroup(ioportid_t port, + ioportmask_t mask, + uint32_t offset); + void _pal_lld_writegroup(ioportid_t port, + ioportmask_t mask, + uint32_t offset, + uint32_t bits); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL */ + +#endif /* _PAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/platform.mk b/os/hal/platforms/LPC17xx/platform.mk new file mode 100644 index 000000000..b3e3f8eed --- /dev/null +++ b/os/hal/platforms/LPC17xx/platform.mk @@ -0,0 +1,14 @@ +# List of all the LPC17xx platform files. +PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC17xx/hal_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/lpc17xx_dma.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/adc_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/gpt_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/pal_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/serial_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/rtc_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/i2c_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC17xx/spi_lld.c + + +# Required include directories +PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC17xx diff --git a/os/hal/platforms/LPC17xx/rtc_lld.c b/os/hal/platforms/LPC17xx/rtc_lld.c new file mode 100644 index 000000000..62acfffc8 --- /dev/null +++ b/os/hal/platforms/LPC17xx/rtc_lld.c @@ -0,0 +1,290 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC17xx/rtc_lld.c + * @brief LPC17xx RTC low level driver. + * + * @addtogroup RTC + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Enable RTC clock. + */ +#define _rtc_clk_enable() \ + LPC_RTC->CCR |= CCR_CLKEN + +/** + * @brief Disable RTC clock. + */ +#define _rtc_clk_disable() \ + LPC_RTC->CCR &= ~CCR_CLKEN + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief RTC interrupt handler. + * + * @isr + */ + +#if LPC17xx_RTC_USE_ALARM || defined(__DOXYGEN__) +CH_IRQ_HANDLER(Vector84) { + uint32_t status; + + CH_IRQ_PROLOGUE(); + + status = LPC_RTC->ILR; + LPC_RTC->ILR = status; /* Clear interrupt flag */ + + if ((status & ILR_RTCALF) && (RTCD1.callback != NULL)) + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM); + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enable access to registers. + * + * @api + */ +void rtc_lld_init(void) { + + if(LPC_RTC->RTC_AUX & RTC_AUX_RTC_OSCF) { /* Set after RTC power was first turn. */ + + LPC_RTC->CCR = CCR_CCALEN; /* Disable calibration and RTC clock. */ + LPC_RTC->CALIBRATION = 0; + LPC_RTC->RTC_AUX = RTC_AUX_RTC_OSCF; /* Clear RTC Oscillator Fail detect flag. */ + + LPC_RTC->CIIR = 0; /* Disable Counter Increment Interrupt. */ + LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */ + LPC_RTC->ILR = ILR_RTCALF | ILR_RTCCIF; /* Clear interrupt flags. */ + + /* Set date to Saturday 01.01.2000 00:00:00 */ + LPC_RTC->SEC = 0; + LPC_RTC->MIN = 0; + LPC_RTC->HOUR = 0; + LPC_RTC->DOM = 1; + LPC_RTC->MONTH = 1; + LPC_RTC->YEAR = 2000; + LPC_RTC->DOW = 6; + LPC_RTC->DOY = 1; + + _rtc_clk_enable(); /* Enable RTC clock. */ + } + +#if LPC17xx_RTC_USE_ALARM + nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_RTC_IRQ_PRIORITY)); +#endif + return; +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to set it on STM32 platform. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCTime structure + * + * @api + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) { + (void)rtcp; + + _rtc_clk_disable(); /* Disable RTC clock. */ + LPC_RTC->SEC = timespec->sec; + LPC_RTC->MIN = timespec->min; + LPC_RTC->HOUR = timespec->hour; + LPC_RTC->DOM = timespec->dom; + LPC_RTC->MONTH = timespec->month; + LPC_RTC->YEAR = timespec->year; + LPC_RTC->DOW = timespec->dow; + LPC_RTC->DOY = timespec->doy; + _rtc_clk_enable(); /* Enable RTC clock. */ + +} + +/** + * @brief Get current time. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCTime structure + * + * @api + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) { + (void)rtcp; + + timespec->sec = LPC_RTC->SEC; + timespec->min = LPC_RTC->MIN; + timespec->hour = LPC_RTC->HOUR; + timespec->dom = LPC_RTC->DOM; + timespec->month = LPC_RTC->MONTH; + timespec->year = LPC_RTC->YEAR; + timespec->dow = LPC_RTC->DOW; + timespec->doy = LPC_RTC->DOY; +} + +/** + * @brief Set alarm time. + * + * @note Default value after BKP domain reset for both comparators is 0. + * @note Function does not performs any checks of alarm time validity. + * + * @param[in] rtcp Pointer to RTC driver structure. + * @param[in] alarm Alarm identifier. Can be 1 or 2. + * @param[in] alarmspec Pointer to a @p RTCAlarm structure. + * + * @api + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + (void)rtcp; + (void)alarm; + LPC_RTC->ALSEC = alarmspec->alsec; + LPC_RTC->ALMIN = alarmspec->almin; + LPC_RTC->ALHOUR = alarmspec->alhour; + LPC_RTC->ALDOM = alarmspec->aldom; + LPC_RTC->ALMON = alarmspec->almonth; + LPC_RTC->ALYEAR = alarmspec->alyear; + LPC_RTC->ALDOW = alarmspec->aldow; + LPC_RTC->ALDOY = alarmspec->aldoy; + +} + +/** + * @brief Get alarm time. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @api + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + (void)rtcp; + (void)alarm; + alarmspec->alsec = LPC_RTC->ALSEC; + alarmspec->almin = LPC_RTC->ALMIN; + alarmspec->alhour = LPC_RTC->ALHOUR; + alarmspec->aldom = LPC_RTC->ALDOM; + alarmspec->almonth = LPC_RTC->ALMON; + alarmspec->alyear = LPC_RTC->ALYEAR; + alarmspec->aldow = LPC_RTC->ALDOW; + alarmspec->aldoy = LPC_RTC->ALDOY; + +} + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + + LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */ + LPC_RTC->ILR = ILR_RTCALF; /* Clear interrupt flag. */ + + if (callback != NULL) { + + /* IRQ sources enabled only after setting up the callback.*/ + rtcp->callback = callback; + LPC_RTC->AMR = 0; /* Enable alarm interrupt. */ + } + else { + + /* Callback set to NULL only after disabling the IRQ sources.*/ + rtcp->callback = NULL; + } +} + +#include "chrtclib.h" + +/** + * @brief Get current time in format suitable for usage in FatFS. + * + * @param[in] rtcp pointer to RTC driver structure + * @return FAT time value. + * + * @api + */ +uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) { + uint32_t fattime; + struct tm timp; + + rtcGetTimeTm(rtcp, &timp); + + fattime = (timp.tm_sec) >> 1; + fattime |= (timp.tm_min) << 5; + fattime |= (timp.tm_hour) << 11; + fattime |= (timp.tm_mday) << 16; + fattime |= (timp.tm_mon + 1) << 21; + fattime |= (timp.tm_year - 80) << 25; + + return fattime; +} + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/rtc_lld.h b/os/hal/platforms/LPC17xx/rtc_lld.h new file mode 100644 index 000000000..1b6a727cf --- /dev/null +++ b/os/hal/platforms/LPC17xx/rtc_lld.h @@ -0,0 +1,279 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC17xx/rtc_lld.h + * @brief LPC17xx RTC low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef _RTC_LLD_H_ +#define _RTC_LLD_H_ + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define ILR_RTCCIF 0x01 +#define ILR_RTCALF 0x02 + +#define CCR_CLKEN 0x01 +#define CCR_CTCRST 0x02 +#define CCR_CCALEN 0x10 + +#define CIIR_IMSEC 0x01 +#define CIIR_IMMIN 0x02 +#define CIIR_IMHOUR 0x04 +#define CIIR_IMDOM 0x08 +#define CIIR_IMDOW 0x10 +#define CIIR_IMDOY 0x20 +#define CIIR_IMMON 0x40 +#define CIIR_IMYEAR 0x80 + +#define AMR_AMRSEC 0x01 +#define AMR_AMRMIN 0x02 +#define AMR_AMRHOUR 0x04 +#define AMR_AMRDOM 0x08 +#define AMR_AMRDOW 0x10 +#define AMR_AMRDOY 0x20 +#define AMR_AMRMON 0x40 +#define AMR_AMRYEAR 0x80 +#define AMR_MASK_ALL 0xFF + +#define RTC_AUX_RTC_OSCF 0x10 + +#define RTC_AUXEN_RTC_OSCFEN 0x10 + +/** + * @brief This RTC implementation supports callbacks. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief One alarm comparator available. + */ +#define RTC_ALARMS 1 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/* + * RTC driver system settings. + */ + +/** + * @brief RTC Alarm enable. + */ +#if !defined(LPC17xx_RTC_USE_ALARM) || defined(__DOXYGEN__) +#define LPC17xx_RTC_USE_ALARM FALSE +#endif + +/** + * @brief RTC IRQ Priority. + */ +#if !defined(LPC17xx_RTC_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_RTC_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct RTCAlarm RTCAlarm; + +/** + * @brief Type of a structure representing an RTC wakeup period. + */ +typedef struct RTCWakeup RTCWakeup; + +/** + * @brief Type of a structure representing an RTC callbacks config. + */ +typedef struct RTCCallbackConfig RTCCallbackConfig; + +/** + * @brief Type of an RTC alarm. + * @details Meaningful on platforms with more than 1 alarm comparator. + */ +typedef uint32_t rtcalarm_t; + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_ALARM = 0 /** Triggered on alarm. */ +} rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Structure representing an RTC callbacks config. + */ +struct RTCCallbackConfig{ + /** + * @brief Generic RTC callback pointer. + */ + rtccb_t callback; +}; + +/** + * @brief Structure representing an RTC time stamp. + */ +struct RTCTime { + /** + * @brief RTC seconds register. + */ + uint8_t sec; + /** + * @brief RTC minutes register. + */ + uint8_t min; + /** + * @brief RTC hours register. + */ + uint8_t hour; + /** + * @brief RTC day of month register. + */ + uint8_t dom; + /** + * @brief RTC month register. + */ + uint8_t month; + /** + * @brief RTC day of week register. + */ + uint8_t dow; + /** + * @brief RTC year register. + */ + uint16_t year; + /** + * @brief RTC day of year register. + */ + uint16_t doy; + +}; + +/** + * @brief Structure representing an RTC alarm time stamp. + */ +struct RTCAlarm { + /** + * @brief RTC alarm seconds register. + */ + uint8_t alsec; + /** + * @brief RTC alarm minutes register. + */ + uint8_t almin; + /** + * @brief RTC alarm hours register. + */ + uint8_t alhour; + /** + * @brief RTC alarm day of month register. + */ + uint8_t aldom; + /** + * @brief RTC alarm month register. + */ + uint8_t almonth; + /** + * @brief RTC alarm day of week register. + */ + uint8_t aldow; + /** + * @brief RTC alarm year register. + */ + uint16_t alyear; + /** + * @brief RTC alarm day of year register. + */ + uint16_t aldoy; + +}; + +/** + * @brief Structure representing an RTC driver. + */ +struct RTCDriver{ + /** + * @brief Callback pointer. + */ + rtccb_t callback; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern RTCDriver RTCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec); + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec); + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); + uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* _RTC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/serial_lld.c b/os/hal/platforms/LPC17xx/serial_lld.c new file mode 100644 index 000000000..03aed7961 --- /dev/null +++ b/os/hal/platforms/LPC17xx/serial_lld.c @@ -0,0 +1,476 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/serial_lld.c + * @brief LPC17xx low level serial driver code. + * + * @addtogroup SERIAL + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__) +/** @brief UART0 serial driver identifier.*/ +SerialDriver SD1; +#endif + +#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__) +/** @brief UART1 serial driver identifier.*/ +SerialDriver SD2; +#endif + +#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__) +/** @brief UART2 serial driver identifier.*/ +SerialDriver SD3; +#endif + +#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__) +/** @brief UART3 serial driver identifier.*/ +SerialDriver SD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** @brief Driver default configuration.*/ +static const SerialConfig default_config = { + SERIAL_DEFAULT_BITRATE, + LCR_WL8 | LCR_STOP1 | LCR_NOPARITY, + FCR_TRIGGER0 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief UART initialization. + * + * @param[in] sdp communication channel associated to the UART + * @param[in] config the architecture-dependent serial driver configuration + */ +static void uart_init(SerialDriver *sdp, const SerialConfig *config) { + LPC_UART_TypeDef *u = sdp->uart; + uint32_t div = 0; + +#if LPC17xx_SERIAL_USE_UART0 + if (&SD1 == sdp) { + div = LPC17xx_SERIAL_UART0_PCLK / (config->sc_speed << 4); + } +#endif + +#if LPC17xx_SERIAL_USE_UART1 + if (&SD2 == sdp) { + div = LPC17xx_SERIAL_UART1_PCLK / (config->sc_speed << 4); + } +#endif + +#if LPC17xx_SERIAL_USE_UART2 + if (&SD3 == sdp) { + div = LPC17xx_SERIAL_UART2_PCLK / (config->sc_speed << 4); + } +#endif + +#if LPC17xx_SERIAL_USE_UART3 + if (&SD4 == sdp) { + div = LPC17xx_SERIAL_UART3_PCLK / (config->sc_speed << 4); + } +#endif + + u->LCR = config->sc_lcr | LCR_DLAB; + u->DLL = div; + u->DLM = div >> 8; + u->LCR = config->sc_lcr; + u->FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | config->sc_fcr; + u->ACR = 0; + u->FDR = 0x10; + u->TER = TER_ENABLE; + u->IER = IER_RBR | IER_STATUS; +} + +/** + * @brief UART de-initialization. + * + * @param[in] u pointer to an UART I/O block + */ +static void uart_deinit(LPC_UART_TypeDef *u) { + + u->LCR = LCR_DLAB; + u->DLL = 1; + u->DLM = 0; + u->LCR = 0; + u->FDR = 0x10; + u->IER = 0; + u->FCR = FCR_RXRESET | FCR_TXRESET; + u->ACR = 0; + u->TER = TER_ENABLE; +} + +/** + * @brief Error handling routine. + * + * @param[in] sdp communication channel associated to the UART + * @param[in] err UART LSR register value + */ +static void set_error(SerialDriver *sdp, IOREG32 err) { + flagsmask_t sts = 0; + + if (err & LSR_OVERRUN) + sts |= SD_OVERRUN_ERROR; + if (err & LSR_PARITY) + sts |= SD_PARITY_ERROR; + if (err & LSR_FRAMING) + sts |= SD_FRAMING_ERROR; + if (err & LSR_BREAK) + sts |= SD_BREAK_DETECTED; + chSysLockFromIsr(); + chnAddFlagsI(sdp, sts); + chSysUnlockFromIsr(); +} + +/** + * @brief Common IRQ handler. + * @note Tries hard to clear all the pending interrupt sources, we don't + * want to go through the whole ISR and have another interrupt soon + * after. + * + * @param[in] u pointer to an UART I/O block + * @param[in] sdp communication channel associated to the UART + */ +static void serve_interrupt(SerialDriver *sdp) { + LPC_UART_TypeDef *u = sdp->uart; + + while (TRUE) { + switch (u->IIR & IIR_SRC_MASK) { + case IIR_SRC_NONE: + return; + case IIR_SRC_ERROR: + set_error(sdp, u->LSR); + break; + case IIR_SRC_TIMEOUT: + case IIR_SRC_RX: + chSysLockFromIsr(); + if (chIQIsEmptyI(&sdp->iqueue)) + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + chSysUnlockFromIsr(); + while (u->LSR & LSR_RBR_FULL) { + chSysLockFromIsr(); + if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK) + chnAddFlagsI(sdp, SD_OVERRUN_ERROR); + chSysUnlockFromIsr(); + } + break; + case IIR_SRC_TX: + { + int i = LPC17xx_SERIAL_FIFO_PRELOAD; + do { + msg_t b; + + chSysLockFromIsr(); + b = chOQGetI(&sdp->oqueue); + chSysUnlockFromIsr(); + if (b < Q_OK) { + u->IER &= ~IER_THRE; + chSysLockFromIsr(); + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + chSysUnlockFromIsr(); + break; + } + u->THR = b; + } while (--i); + } + break; + default: + (void) u->THR; + (void) u->RBR; + } + } +} + +/** + * @brief Attempts a TX FIFO preload. + */ +static void preload(SerialDriver *sdp) { + LPC_UART_TypeDef *u = sdp->uart; + + if (u->LSR & LSR_THRE) { + int i = LPC17xx_SERIAL_FIFO_PRELOAD; + do { + msg_t b = chOQGetI(&sdp->oqueue); + if (b < Q_OK) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + return; + } + u->THR = b; + } while (--i); + } + u->IER |= IER_THRE; +} + +/** + * @brief Driver SD1 output notification. + */ +#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__) +static void notify1(GenericQueue *qp) { + + (void)qp; + preload(&SD1); +} +#endif + +/** + * @brief Driver SD2 output notification. + */ +#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__) +static void notify2(GenericQueue *qp) { + + (void)qp; + preload(&SD2); +} +#endif + +/** + * @brief Driver SD3 output notification. + */ +#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__) +static void notify3(GenericQueue *qp) { + + (void)qp; + preload(&SD3); +} +#endif + +/** + * @brief Driver SD4 output notification. + */ +#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__) +static void notify4(GenericQueue *qp) { + + (void)qp; + preload(&SD4); +} +#endif +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief UART0 IRQ handler. + * + * @isr + */ +#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(Vector54) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD1); + + CH_IRQ_EPILOGUE(); +} +#endif + +/** + * @brief UART1 IRQ handler. + * + * @isr + */ +#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(Vector58) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD2); + + CH_IRQ_EPILOGUE(); +} +#endif + +/** + * @brief UART2 IRQ handler. + * + * @isr + */ +#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(Vector5C) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD3); + + CH_IRQ_EPILOGUE(); +} +#endif + +/** + * @brief UART3 IRQ handler. + * + * @isr + */ +#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(Vector60) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD4); + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if LPC17xx_SERIAL_USE_UART0 + sdObjectInit(&SD1, NULL, notify1); + SD1.uart = (LPC_UART_TypeDef*) LPC_UART0; +#endif + +#if LPC17xx_SERIAL_USE_UART1 + sdObjectInit(&SD2, NULL, notify2); + SD2.uart = (LPC_UART_TypeDef*) LPC_UART1; +#endif + +#if LPC17xx_SERIAL_USE_UART2 + sdObjectInit(&SD3, NULL, notify3); + SD3.uart = (LPC_UART_TypeDef*) LPC_UART2; +#endif + +#if LPC17xx_SERIAL_USE_UART3 + sdObjectInit(&SD4, NULL, notify4); + SD4.uart = (LPC_UART_TypeDef*) LPC_UART3; +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) + config = &default_config; + + if (sdp->state == SD_STOP) { +#if LPC17xx_SERIAL_USE_UART0 + if (&SD1 == sdp) { + LPC_SC->PCONP |= (1 << 3); + nvicEnableVector(UART0_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART0_IRQ_PRIORITY)); + } +#endif + +#if LPC17xx_SERIAL_USE_UART1 + if (&SD2 == sdp) { + LPC_SC->PCONP |= (1 << 4); + nvicEnableVector(UART1_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART1_IRQ_PRIORITY)); + } +#endif + +#if LPC17xx_SERIAL_USE_UART2 + if (&SD3 == sdp) { + LPC_SC->PCONP |= (1 << 24); + nvicEnableVector(UART2_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART2_IRQ_PRIORITY)); + } +#endif + +#if LPC17xx_SERIAL_USE_UART3 + if (&SD4 == sdp) { + LPC_SC->PCONP |= (1 << 25); + nvicEnableVector(UART3_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART3_IRQ_PRIORITY)); + } +#endif + } + uart_init(sdp, config); +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the UART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + uart_deinit(sdp->uart); +#if LPC17xx_SERIAL_USE_UART0 + if (&SD1 == sdp) { + LPC_SC->PCONP &= ~(1 << 3); + nvicDisableVector(UART0_IRQn); + return; + } +#endif + +#if LPC17xx_SERIAL_USE_UART1 + if (&SD2 == sdp) { + LPC_SC->PCONP &= ~(1 << 4); + nvicDisableVector(UART1_IRQn); + return; + } +#endif + +#if LPC17xx_SERIAL_USE_UART2 + if (&SD3 == sdp) { + LPC_SC->PCONP &= ~(1 << 24); + nvicDisableVector(UART2_IRQn); + return; + } +#endif + +#if LPC17xx_SERIAL_USE_UART3 + if (&SD4 == sdp) { + LPC_SC->PCONP &= ~(1 << 25); + nvicDisableVector(UART3_IRQn); + return; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/serial_lld.h b/os/hal/platforms/LPC17xx/serial_lld.h new file mode 100644 index 000000000..75d68795d --- /dev/null +++ b/os/hal/platforms/LPC17xx/serial_lld.h @@ -0,0 +1,268 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/serial_lld.h + * @brief LPC17xx low level serial driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef _SERIAL_LLD_H_ +#define _SERIAL_LLD_H_ + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define IIR_SRC_MASK 0x0F +#define IIR_SRC_NONE 0x01 +#define IIR_SRC_MODEM 0x00 +#define IIR_SRC_TX 0x02 +#define IIR_SRC_RX 0x04 +#define IIR_SRC_ERROR 0x06 +#define IIR_SRC_TIMEOUT 0x0C + +#define IER_RBR 1 +#define IER_THRE 2 +#define IER_STATUS 4 + +#define LCR_WL5 0 +#define LCR_WL6 1 +#define LCR_WL7 2 +#define LCR_WL8 3 +#define LCR_STOP1 0 +#define LCR_STOP2 4 +#define LCR_NOPARITY 0 +#define LCR_PARITYODD 0x08 +#define LCR_PARITYEVEN 0x18 +#define LCR_PARITYONE 0x28 +#define LCR_PARITYZERO 0x38 +#define LCR_BREAK_ON 0x40 +#define LCR_DLAB 0x80 + +#define FCR_ENABLE 1 +#define FCR_RXRESET 2 +#define FCR_TXRESET 4 +#define FCR_TRIGGER0 0 +#define FCR_TRIGGER1 0x40 +#define FCR_TRIGGER2 0x80 +#define FCR_TRIGGER3 0xC0 + +#define LSR_RBR_FULL 1 +#define LSR_OVERRUN 2 +#define LSR_PARITY 4 +#define LSR_FRAMING 8 +#define LSR_BREAK 0x10 +#define LSR_THRE 0x20 +#define LSR_TEMT 0x40 +#define LSR_RXFE 0x80 + +#define TER_ENABLE 0x80 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief UART0 driver enable switch. + * @details If set to @p TRUE the support for UART0 is included. + * @note The default is @p TRUE . + */ +#if !defined(LPC17xx_SERIAL_USE_UART0) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_USE_UART0 TRUE +#endif + +/** + * @brief UART1 driver enable switch. + * @details If set to @p TRUE the support for UART1 is included. + * @note The default is @p TRUE . + */ +#if !defined(LPC17xx_SERIAL_USE_UART1) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_USE_UART1 TRUE +#endif + +/** + * @brief UART2 driver enable switch. + * @details If set to @p TRUE the support for UART2 is included. + * @note The default is @p TRUE . + */ +#if !defined(LPC17xx_SERIAL_USE_UART2) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_USE_UART2 TRUE +#endif + +/** + * @brief UART3 driver enable switch. + * @details If set to @p TRUE the support for UART3 is included. + * @note The default is @p TRUE . + */ +#if !defined(LPC17xx_SERIAL_USE_UART3) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_USE_UART3 TRUE +#endif + +/** + * @brief FIFO preload parameter. + * @details Configuration parameter, this values defines how many bytes are + * preloaded in the HW transmit FIFO for each interrupt, the maximum + * value is 16 the minimum is 1. + * @note An high value reduces the number of interrupts generated but can + * also increase the worst case interrupt response time because the + * preload loops. + */ +#if !defined(LPC17xx_SERIAL_FIFO_PRELOAD) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_FIFO_PRELOAD 16 +#endif + +/** + * @brief UART0 interrupt priority level setting. + */ +#if !defined(LPC17xx_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3 +#endif + +/** + * @brief UART1 interrupt priority level setting. + */ +#if !defined(LPC17xx_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_UART1_IRQ_PRIORITY 3 +#endif + +/** + * @brief UART2 interrupt priority level setting. + */ +#if !defined(LPC17xx_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_UART2_IRQ_PRIORITY 3 +#endif + +/** + * @brief UART3 interrupt priority level setting. + */ +#if !defined(LPC17xx_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ +#if (LPC17xx_SERIAL_FIFO_PRELOAD < 1) || (LPC17xx_SERIAL_FIFO_PRELOAD > 16) +#error "invalid LPC17xx_SERIAL_FIFO_PRELOAD setting" +#endif + +/** + * @brief UART0 clock. + */ +#define LPC17xx_SERIAL_UART0_PCLK LPC17xx_PCLK + +/** + * @brief UART1 clock. + */ +#define LPC17xx_SERIAL_UART1_PCLK LPC17xx_PCLK + +/** + * @brief UART2 clock. + */ +#define LPC17xx_SERIAL_UART2_PCLK LPC17xx_PCLK + +/** + * @brief UART3 clock. + */ +#define LPC17xx_SERIAL_UART3_PCLK LPC17xx_PCLK + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief LPC17xx Serial Driver configuration structure. + * @details An instance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t sc_speed; + /** + * @brief Initialization value for the LCR register. + */ + uint32_t sc_lcr; + /** + * @brief Initialization value for the FCR register. + */ + uint32_t sc_fcr; +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + InputQueue iqueue; \ + /* Output queue.*/ \ + OutputQueue oqueue; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* End of the mandatory fields.*/ \ + /* Pointer to the USART registers block.*/ \ + LPC_UART_TypeDef *uart; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC17xx_SERIAL_USE_UART0 && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif + +#if LPC17xx_SERIAL_USE_UART1 && !defined(__DOXYGEN__) +extern SerialDriver SD2; +#endif + +#if LPC17xx_SERIAL_USE_UART2 && !defined(__DOXYGEN__) +extern SerialDriver SD3; +#endif + +#if LPC17xx_SERIAL_USE_UART3 && !defined(__DOXYGEN__) +extern SerialDriver SD4; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL */ + +#endif /* _SERIAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/spi_lld.c b/os/hal/platforms/LPC17xx/spi_lld.c new file mode 100644 index 000000000..483739aba --- /dev/null +++ b/os/hal/platforms/LPC17xx/spi_lld.c @@ -0,0 +1,387 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/spi_lld.c + * @brief LPC17xx low level SPI driver code. + * + * @addtogroup SPI + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__) +/** @brief SPI1 driver identifier.*/ +SPIDriver SPID1; +#endif + +#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__) +/** @brief SPI2 driver identifier.*/ +SPIDriver SPID2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Preloads the transmit FIFO. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void ssp_fifo_preload(SPIDriver *spip) { + LPC_SSP_TypeDef *ssp = spip->ssp; + uint32_t n = spip->txcnt > LPC17xx_SSP_FIFO_DEPTH ? + LPC17xx_SSP_FIFO_DEPTH : spip->txcnt; + + while(((ssp->SR & SR_TNF) != 0) && (n > 0)) { + if (spip->txptr != NULL) { + if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) { + const uint16_t *p = spip->txptr; + ssp->DR = *p++; + spip->txptr = p; + } + else { + const uint8_t *p = spip->txptr; + ssp->DR = *p++; + spip->txptr = p; + } + } + else + ssp->DR = 0xFFFFFFFF; + n--; + spip->txcnt--; + } +} + +/** + * @brief Common IRQ handler. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void spi_serve_interrupt(SPIDriver *spip) { + LPC_SSP_TypeDef *ssp = spip->ssp; + + if ((ssp->MIS & MIS_ROR) != 0) { + /* The overflow condition should never happen because priority is given + to receive but a hook macro is provided anyway...*/ + LPC17xx_SPI_SSP_ERROR_HOOK(spip); + } + ssp->ICR = ICR_RT | ICR_ROR; + while ((ssp->SR & SR_RNE) != 0) { + if (spip->rxptr != NULL) { + if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) { + uint16_t *p = spip->rxptr; + *p++ = ssp->DR; + spip->rxptr = p; + } + else { + uint8_t *p = spip->rxptr; + *p++ = ssp->DR; + spip->rxptr = p; + } + } + else + (void)ssp->DR; + if (--spip->rxcnt == 0) { + chDbgAssert(spip->txcnt == 0, + "spi_serve_interrupt(), #1", "counter out of synch"); + /* Stops the IRQ sources.*/ + ssp->IMSC = 0; + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + return; + } + } + ssp_fifo_preload(spip); + if (spip->txcnt == 0) + ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_RX; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__) +/** + * @brief SSP0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector78) { + + CH_IRQ_PROLOGUE(); + + spi_serve_interrupt(&SPID1); + + CH_IRQ_EPILOGUE(); +} +#endif + +#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__) +/** + * @brief SSP1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector7C) { + + CH_IRQ_PROLOGUE(); + + spi_serve_interrupt(&SPID2); + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if LPC17xx_SPI_USE_SSP0 + spiObjectInit(&SPID1); + SPID1.ssp = LPC_SSP0; +#endif /* LPC17xx_SPI_USE_SSP0 */ + +#if LPC17xx_SPI_USE_SSP1 + spiObjectInit(&SPID2); + SPID2.ssp = LPC_SSP1; +#endif /* LPC17xx_SPI_USE_SSP0 */ +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + + if (spip->state == SPI_STOP) { + /* Clock activation.*/ +#if LPC17xx_SPI_USE_SSP0 + if (&SPID1 == spip) { + LPC_SC->PCONP |= (1UL << 21); + LPC_SC->PCLKSEL0 &= (PCLKSEL_MASK << 20); + LPC_SC->PCLKSEL0 |= (LPC17xx_SPI_SSP0_PCLKSEL << 20); + nvicEnableVector(SSP0_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP0_IRQ_PRIORITY)); + } +#endif +#if LPC17xx_SPI_USE_SSP1 + if (&SPID2 == spip) { + LPC_SC->PCONP |= (1UL << 10); + LPC_SC->PCLKSEL1 &= (PCLKSEL_MASK << 10); + LPC_SC->PCLKSEL1 |= (LPC17xx_SPI_SSP0_PCLKSEL << 10); + nvicEnableVector(SSP1_IRQn, + CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP1_IRQ_PRIORITY)); + } +#endif + } + /* Configuration.*/ + spip->ssp->CR1 = 0; + spip->ssp->ICR = ICR_RT | ICR_ROR; + spip->ssp->CR0 = spip->config->cr0; + spip->ssp->CPSR = spip->config->cpsr; + spip->ssp->CR1 = CR1_SSE; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + if (spip->state != SPI_STOP) { + spip->ssp->CR1 = 0; + spip->ssp->CR0 = 0; + spip->ssp->CPSR = 0; +#if LPC17xx_SPI_USE_SSP0 + if (&SPID1 == spip) { + LPC_SC->PCONP &= ~(1UL << 21); + nvicDisableVector(SSP0_IRQn); + } +#endif +#if LPC17xx_SPI_USE_SSP1 + if (&SPID2 == spip) { + LPC_SC->PCONP &= ~(1UL << 10); + nvicDisableVector(SSP1_IRQn); + } +#endif + } +} + +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + palClearPad(spip->config->ssport, spip->config->sspad); +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + palSetPad(spip->config->ssport, spip->config->sspad); +} + +/** + * @brief Ignores data on the SPI bus. + * @details This function transmits a series of idle words on the SPI bus and + * ignores the received data. This function can be invoked even + * when a slave select signal has not been yet asserted. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + spip->rxptr = NULL; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + spip->rxptr = NULL; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + spip->ssp->DR = (uint32_t)frame; + while ((spip->ssp->SR & SR_RNE) == 0) + ; + return (uint16_t)spip->ssp->DR; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/spi_lld.h b/os/hal/platforms/LPC17xx/spi_lld.h new file mode 100644 index 000000000..cc1674519 --- /dev/null +++ b/os/hal/platforms/LPC17xx/spi_lld.h @@ -0,0 +1,337 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file LPC17xx/spi_lld.h + * @brief LPC17xx low level SPI driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef _SPI_LLD_H_ +#define _SPI_LLD_H_ + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Hardware FIFO depth. + */ +#define LPC17xx_SSP_FIFO_DEPTH 8 + +#define CR0_DSSMASK 0x0F +#define CR0_DSS4BIT 3 +#define CR0_DSS5BIT 4 +#define CR0_DSS6BIT 5 +#define CR0_DSS7BIT 6 +#define CR0_DSS8BIT 7 +#define CR0_DSS9BIT 8 +#define CR0_DSS10BIT 9 +#define CR0_DSS11BIT 0xA +#define CR0_DSS12BIT 0xB +#define CR0_DSS13BIT 0xC +#define CR0_DSS14BIT 0xD +#define CR0_DSS15BIT 0xE +#define CR0_DSS16BIT 0xF +#define CR0_FRFSPI 0 +#define CR0_FRFSSI 0x10 +#define CR0_FRFMW 0x20 +#define CR0_CPOL 0x40 +#define CR0_CPHA 0x80 +#define CR0_CLOCKRATE(n) ((n) << 8) + +#define CR1_LBM 1 +#define CR1_SSE 2 +#define CR1_MS 4 +#define CR1_SOD 8 + +#define SR_TFE 1 +#define SR_TNF 2 +#define SR_RNE 4 +#define SR_RFF 8 +#define SR_BSY 16 + +#define IMSC_ROR 1 +#define IMSC_RT 2 +#define IMSC_RX 4 +#define IMSC_TX 8 + +#define RIS_ROR 1 +#define RIS_RT 2 +#define RIS_RX 4 +#define RIS_TX 8 + +#define MIS_ROR 1 +#define MIS_RT 2 +#define MIS_RX 4 +#define MIS_TX 8 + +#define ICR_ROR 1 +#define ICR_RT 2 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for device SSP0 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_SPI_USE_SSP0) || defined(__DOXYGEN__) +#define LPC17xx_SPI_USE_SSP0 TRUE +#endif + +/** + * @brief SPI2 driver enable switch. + * @details If set to @p TRUE the support for device SSP1 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC17xx_SPI_USE_SSP1) || defined(__DOXYGEN__) +#define LPC17xx_SPI_USE_SSP1 FALSE +#endif + +/** + * @brief SSP0 PCLK divider. + */ +#if !defined(LPC17xx_SPI_SSP0CLKDIV) || defined(__DOXYGEN__) +#define LPC17xx_SPI_SSP0CLKDIV 1 +#endif + +/** + * @brief SSP1 PCLK divider. + */ +#if !defined(LPC17xx_SPI_SSP1CLKDIV) || defined(__DOXYGEN__) +#define LPC17xx_SPI_SSP1CLKDIV 1 +#endif + +/** + * @brief SPI0 interrupt priority level setting. + */ +#if !defined(LPC17xx_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SPI_SSP0_IRQ_PRIORITY 5 +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(LPC17xx_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC17xx_SPI_SSP1_IRQ_PRIORITY 5 +#endif + +/** + * @brief Overflow error hook. + * @details The default action is to stop the system. + */ +#if !defined(LPC17xx_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__) +#define LPC17xx_SPI_SSP_ERROR_HOOK(spip) chSysHalt() +#endif + +#if LPC17xx_SPI_SSP0CLKDIV == 1 +#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK +#elif LPC17xx_SPI_SSP0CLKDIV == 2 +#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_2 +#elif LPC17xx_SPI_SSP0CLKDIV == 4 +#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_4 +#elif LPC17xx_SPI_SSP0CLKDIV == 8 +#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_8 +#else +#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)" +#endif + +#if LPC17xx_SPI_SSP1CLKDIV == 1 +#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK +#elif LPC17xx_SPI_SSP1CLKDIV == 2 +#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_2 +#elif LPC17xx_SPI_SSP1CLKDIV == 4 +#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_4 +#elif LPC17xx_SPI_SSP1CLKDIV == 8 +#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_8 +#else +#error "Invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)" +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (LPC17xx_SPI_SSP0CLKDIV != 1) && (LPC17xx_SPI_SSP0CLKDIV != 2) && \ + (LPC17xx_SPI_SSP0CLKDIV != 4) && (LPC17xx_SPI_SSP0CLKDIV != 8) +#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)" +#endif + +#if (LPC17xx_SPI_SSP1CLKDIV != 1) && (LPC17xx_SPI_SSP1CLKDIV != 2) && \ + (LPC17xx_SPI_SSP1CLKDIV != 4) && (LPC17xx_SPI_SSP1CLKDIV != 8) +#error "invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)" +#endif + +#if !LPC17xx_SPI_USE_SSP0 && !LPC17xx_SPI_USE_SSP1 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +/** + * @brief SSP0 clock. + */ +#define LPC17xx_SPI_SSP0_PCLK \ + (LPC17xx_CCLK / LPC17xx_SPI_SSP0CLKDIV) + +/** + * @brief SSP1 clock. + */ +#define LPC17xx_SPI_SSP1_PCLK \ + (LPC17xx_CCLK / LPC17xx_SPI_SSP1CLKDIV) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an SPI driver. + */ +typedef struct SPIDriver SPIDriver; + +/** + * @brief SPI notification callback type. + * + * @param[in] spip pointer to the @p SPIDriver object triggering the + * callback + */ +typedef void (*spicallback_t)(SPIDriver *spip); + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Operation complete callback or @p NULL. + */ + spicallback_t end_cb; + /* End of the mandatory fields.*/ + /** + * @brief The chip select line port. + */ + ioportid_t ssport; + /** + * @brief The chip select line pad number. + */ + uint16_t sspad; + /** + * @brief SSP CR0 initialization data. + */ + uint16_t cr0; + /** + * @brief SSP CPSR initialization data. + */ + uint32_t cpsr; +} SPIConfig; + +/** + * @brief Structure representing a SPI driver. + */ +struct SPIDriver { + /** + * @brief Driver state. + */ + spistate_t state; + /** + * @brief Current configuration data. + */ + const SPIConfig *config; +#if SPI_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + Thread *thread; +#endif /* SPI_USE_WAIT */ +#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + Mutex mutex; +#elif CH_USE_SEMAPHORES + Semaphore semaphore; +#endif +#endif /* SPI_USE_MUTUAL_EXCLUSION */ +#if defined(SPI_DRIVER_EXT_FIELDS) + SPI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the SSP registers block. + */ + LPC_SSP_TypeDef *ssp; + /** + * @brief Number of bytes yet to be received. + */ + uint32_t rxcnt; + /** + * @brief Receive pointer or @p NULL. + */ + void *rxptr; + /** + * @brief Number of bytes yet to be transmitted. + */ + uint32_t txcnt; + /** + * @brief Transmit pointer or @p NULL. + */ + const void *txptr; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC17xx_SPI_USE_SSP0 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#if LPC17xx_SPI_USE_SSP1 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* _SPI_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC17xx/system_LPC17xx.h b/os/hal/platforms/LPC17xx/system_LPC17xx.h new file mode 100644 index 000000000..d72cb509e --- /dev/null +++ b/os/hal/platforms/LPC17xx/system_LPC17xx.h @@ -0,0 +1,64 @@ +/**************************************************************************//** + * @file system_LPC17xx.h + * @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File + * for the NXP LPC17xx Device Series + * @version V1.02 + * @date 08. September 2009 + * + * @note + * Copyright (C) 2009 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. This file can be freely distributed + * within development tools that are supporting such ARM based processors. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + + +#ifndef __SYSTEM_LPC17xx_H +#define __SYSTEM_LPC17xx_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ + + +/** + * Initialize the system + * + * @param none + * @return none + * + * @brief Setup the microcontroller system. + * Initialize the System and update the SystemCoreClock variable. + */ +extern void SystemInit (void); + +/** + * Update SystemCoreClock variable + * + * @param none + * @return none + * + * @brief Updates the SystemCoreClock with current core Clock + * retrieved from cpu registers. + */ +extern void SystemCoreClockUpdate (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_LPC17xx_H */ diff --git a/os/ports/GCC/ARMCMx/LPC17xx/cmparams.h b/os/ports/GCC/ARMCMx/LPC17xx/cmparams.h new file mode 100644 index 000000000..9483509dc --- /dev/null +++ b/os/ports/GCC/ARMCMx/LPC17xx/cmparams.h @@ -0,0 +1,62 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file GCC/ARMCMx/LPC17xx/cmparams.h + * @brief ARM Cortex-M3 LPC17xx Specific Parameters. + * + * @defgroup ARMCMx_LPC13xx LPC17xx Specific Parameters + * @ingroup ARMCMx_SPECIFIC + * @details This file contains the Cortex-M3 specific parameters for the + * LPC17xx platform. + * @{ + */ + +#ifndef _CMPARAMS_H_ +#define _CMPARAMS_H_ + +/** + * @brief Cortex core model. + */ +#define CORTEX_MODEL CORTEX_M3 + +/** + * @brief Systick unit presence. + */ +#define CORTEX_HAS_ST TRUE + +/** + * @brief Memory Protection unit presence. + */ +#define CORTEX_HAS_MPU TRUE + +/** + * @brief Floating Point unit presence. + */ +#define CORTEX_HAS_FPU FALSE + +/** + * @brief Number of bits in priority masks. + */ +#define CORTEX_PRIORITY_BITS 3 + +#endif /* _CMPARAMS_H_ */ + +/** @} */ diff --git a/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1766.ld b/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1766.ld new file mode 100644 index 000000000..2a12d97e3 --- /dev/null +++ b/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1766.ld @@ -0,0 +1,153 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * LPC1766 memory setup. + */ +__main_stack_size__ = 0x0200; +__process_stack_size__ = 0x0200; + +MEMORY +{ + flash : org = 0x00000000, len = 256k + ram : org = 0x10000000, len = 32k + ramahb : org = 0x2007c000, len = 32k +} + +__ram_start__ = ORIGIN(ram); +__ram_size__ = LENGTH(ram); +__ram_end__ = __ram_start__ + __ram_size__; + +ENTRY(ResetHandler) + +SECTIONS +{ + . = 0; + _text = .; + + startup : ALIGN(16) SUBALIGN(16) + { + KEEP(*(vectors)) + } > flash + + constructors : ALIGN(4) SUBALIGN(4) + { + PROVIDE(__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE(__init_array_end = .); + } > flash + + destructors : ALIGN(4) SUBALIGN(4) + { + PROVIDE(__fini_array_start = .); + KEEP(*(.fini_array)) + KEEP(*(SORT(.fini_array.*))) + PROVIDE(__fini_array_end = .); + } > flash + + .text : ALIGN(16) SUBALIGN(16) + { + *(.text.startup.*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + } > flash + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > flash + + .ARM.exidx : { + PROVIDE(__exidx_start = .); + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + PROVIDE(__exidx_end = .); + } > flash + + .eh_frame_hdr : + { + *(.eh_frame_hdr) + } > flash + + .eh_frame : ONLY_IF_RO + { + *(.eh_frame) + } > flash + + .textalign : ONLY_IF_RO + { + . = ALIGN(8); + } > flash + + _etext = .; + _textdata = _etext; + + .stacks : + { + . = ALIGN(8); + __main_stack_base__ = .; + . += __main_stack_size__; + . = ALIGN(8); + __main_stack_end__ = .; + __process_stack_base__ = .; + __main_thread_stack_base__ = .; + . += __process_stack_size__; + . = ALIGN(8); + __process_stack_end__ = .; + __main_thread_stack_end__ = .; + } > ram + + .data : + { + . = ALIGN(4); + PROVIDE(_data = .); + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + PROVIDE(_edata = .); + } > ram AT > flash + + .bss : + { + . = ALIGN(4); + PROVIDE(_bss_start = .); + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + PROVIDE(_bss_end = .); + } > ram +} + +PROVIDE(end = .); +_end = .; + +__heap_base__ = _end; +__heap_end__ = __ram_end__; diff --git a/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1769.ld b/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1769.ld new file mode 100644 index 000000000..dc5c1feb8 --- /dev/null +++ b/os/ports/GCC/ARMCMx/LPC17xx/ld/LPC1769.ld @@ -0,0 +1,153 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * LPC1766 memory setup. + */ +__main_stack_size__ = 0x0200; +__process_stack_size__ = 0x0200; + +MEMORY +{ + flash : org = 0x00000000, len = 512k + ram : org = 0x10000000, len = 32k + ramahb : org = 0x2007c000, len = 32k +} + +__ram_start__ = ORIGIN(ram); +__ram_size__ = LENGTH(ram); +__ram_end__ = __ram_start__ + __ram_size__; + +ENTRY(ResetHandler) + +SECTIONS +{ + . = 0; + _text = .; + + startup : ALIGN(16) SUBALIGN(16) + { + KEEP(*(vectors)) + } > flash + + constructors : ALIGN(4) SUBALIGN(4) + { + PROVIDE(__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE(__init_array_end = .); + } > flash + + destructors : ALIGN(4) SUBALIGN(4) + { + PROVIDE(__fini_array_start = .); + KEEP(*(.fini_array)) + KEEP(*(SORT(.fini_array.*))) + PROVIDE(__fini_array_end = .); + } > flash + + .text : ALIGN(16) SUBALIGN(16) + { + *(.text.startup.*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + } > flash + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > flash + + .ARM.exidx : { + PROVIDE(__exidx_start = .); + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + PROVIDE(__exidx_end = .); + } > flash + + .eh_frame_hdr : + { + *(.eh_frame_hdr) + } > flash + + .eh_frame : ONLY_IF_RO + { + *(.eh_frame) + } > flash + + .textalign : ONLY_IF_RO + { + . = ALIGN(8); + } > flash + + _etext = .; + _textdata = _etext; + + .stacks : + { + . = ALIGN(8); + __main_stack_base__ = .; + . += __main_stack_size__; + . = ALIGN(8); + __main_stack_end__ = .; + __process_stack_base__ = .; + __main_thread_stack_base__ = .; + . += __process_stack_size__; + . = ALIGN(8); + __process_stack_end__ = .; + __main_thread_stack_end__ = .; + } > ram + + .data : + { + . = ALIGN(4); + PROVIDE(_data = .); + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + PROVIDE(_edata = .); + } > ram AT > flash + + .bss : + { + . = ALIGN(4); + PROVIDE(_bss_start = .); + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + PROVIDE(_bss_end = .); + } > ram +} + +PROVIDE(end = .); +_end = .; + +__heap_base__ = _end; +__heap_end__ = __ram_end__; diff --git a/os/ports/GCC/ARMCMx/LPC17xx/port.mk b/os/ports/GCC/ARMCMx/LPC17xx/port.mk new file mode 100644 index 000000000..e98993ce2 --- /dev/null +++ b/os/ports/GCC/ARMCMx/LPC17xx/port.mk @@ -0,0 +1,15 @@ +# List of the ChibiOS/RT Cortex-M3 LPC17xx port files. +PORTSRC = $(CHIBIOS)/os/ports/GCC/ARMCMx/crt0.c \ + $(CHIBIOS)/os/ports/GCC/ARMCMx/LPC17xx/vectors.c \ + ${CHIBIOS}/os/ports/GCC/ARMCMx/chcore.c \ + ${CHIBIOS}/os/ports/GCC/ARMCMx/chcore_v7m.c \ + ${CHIBIOS}/os/ports/common/ARMCMx/nvic.c + +PORTASM = + +PORTINC = ${CHIBIOS}/os/ports/common/ARMCMx/CMSIS/include \ + ${CHIBIOS}/os/ports/common/ARMCMx \ + ${CHIBIOS}/os/ports/GCC/ARMCMx \ + ${CHIBIOS}/os/ports/GCC/ARMCMx/LPC17xx + +PORTLD = ${CHIBIOS}/os/ports/GCC/ARMCMx/LPC17xx/ld diff --git a/os/ports/GCC/ARMCMx/LPC17xx/vectors.c b/os/ports/GCC/ARMCMx/LPC17xx/vectors.c new file mode 100644 index 000000000..cc2d72133 --- /dev/null +++ b/os/ports/GCC/ARMCMx/LPC17xx/vectors.c @@ -0,0 +1,205 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file GCC/ARMCMx/LPC13xx/vectors.c + * @brief Interrupt vectors for the LPC17xx family. + * + * @defgroup ARMCMx_LPC17xx_VECTORS LPC17xx Interrupt Vectors + * @ingroup ARMCMx_SPECIFIC + * @details Interrupt vectors for the LPC17xx family. + * @{ + */ + +#include "ch.h" + +/** + * @brief Type of an IRQ vector. + */ +typedef void (*irq_vector_t)(void); + +/** + * @brief Type of a structure representing the whole vectors table. + */ +typedef struct { + uint32_t *init_stack; + irq_vector_t reset_vector; + irq_vector_t nmi_vector; + irq_vector_t hardfault_vector; + irq_vector_t memmanage_vector; + irq_vector_t busfault_vector; + irq_vector_t usagefault_vector; + irq_vector_t vector1c; + irq_vector_t vector20; + irq_vector_t vector24; + irq_vector_t vector28; + irq_vector_t svcall_vector; + irq_vector_t debugmonitor_vector; + irq_vector_t vector34; + irq_vector_t pendsv_vector; + irq_vector_t systick_vector; + irq_vector_t vectors[35]; +} vectors_t; + +#if !defined(__DOXYGEN__) +extern uint32_t __main_stack_end__; +extern void ResetHandler(void); +extern void NMIVector(void); +extern void HardFaultVector(void); +extern void MemManageVector(void); +extern void BusFaultVector(void); +extern void UsageFaultVector(void); +extern void Vector1C(void); +extern void Vector20(void); +extern void Vector24(void); +extern void Vector28(void); +extern void SVCallVector(void); +extern void DebugMonitorVector(void); +extern void Vector34(void); +extern void PendSVVector(void); +extern void SysTickVector(void); +extern void Vector40(void); +extern void Vector44(void); +extern void Vector48(void); +extern void Vector4C(void); +extern void Vector50(void); +extern void Vector54(void); +extern void Vector58(void); +extern void Vector5C(void); +extern void Vector60(void); +extern void Vector64(void); +extern void Vector68(void); +extern void Vector6C(void); +extern void Vector70(void); +extern void Vector74(void); +extern void Vector78(void); +extern void Vector7C(void); +extern void Vector80(void); +extern void Vector84(void); +extern void Vector88(void); +extern void Vector8C(void); +extern void Vector90(void); +extern void Vector94(void); +extern void Vector98(void); +extern void Vector9C(void); +extern void VectorA0(void); +extern void VectorA4(void); +extern void VectorA8(void); +extern void VectorAC(void); +extern void VectorB0(void); +extern void VectorB4(void); +extern void VectorB8(void); +extern void VectorBC(void); +extern void VectorC0(void); +extern void VectorC4(void); +extern void VectorC8(void); +#endif + +/** + * @brief LPC17xx vectors table. + */ +#if !defined(__DOXYGEN__) +__attribute__ ((section("vectors"))) +#endif +vectors_t _vectors = { + &__main_stack_end__,ResetHandler, NMIVector, HardFaultVector, + MemManageVector, BusFaultVector, UsageFaultVector, Vector1C, + Vector20, Vector24, Vector28, SVCallVector, + DebugMonitorVector, Vector34, PendSVVector, SysTickVector, + { + Vector40, Vector44, Vector48, Vector4C, + Vector50, Vector54, Vector58, Vector5C, + Vector60, Vector64, Vector68, Vector6C, + Vector70, Vector74, Vector78, Vector7C, + Vector80, Vector84, Vector88, Vector8C, + Vector90, Vector94, Vector98, Vector9C, + VectorA0, VectorA4, VectorA8, VectorAC, + VectorB0, VectorB4, VectorB8, VectorBC, + VectorC0, VectorC4, VectorC8 + } +}; + +/** + * @brief Unhandled exceptions handler. + * @details Any undefined exception vector points to this function by default. + * This function simply stops the system into an infinite loop. + * + * @notapi + */ +#if !defined(__DOXYGEN__) +__attribute__ ((naked)) +#endif +void _unhandled_exception(void) { + + while (TRUE) + ; +} + +void NMIVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void HardFaultVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void MemManageVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void BusFaultVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void UsageFaultVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector1C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector20(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector24(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector28(void) __attribute__((weak, alias("_unhandled_exception"))); +void SVCallVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void DebugMonitorVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector34(void) __attribute__((weak, alias("_unhandled_exception"))); +void PendSVVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void SysTickVector(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector40(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector44(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector48(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector4C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector50(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector54(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector58(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector5C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector60(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector64(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector68(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector6C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector70(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector74(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector78(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector7C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector80(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector84(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector88(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector8C(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector90(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector94(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector98(void) __attribute__((weak, alias("_unhandled_exception"))); +void Vector9C(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorA0(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorA4(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorA8(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorAC(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorB0(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorB4(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorB8(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorBC(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorC0(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorC4(void) __attribute__((weak, alias("_unhandled_exception"))); +void VectorC8(void) __attribute__((weak, alias("_unhandled_exception"))); + +/** @} */ diff --git a/os/various/chrtclib.c b/os/various/chrtclib.c index f2616d460..6fcb3de41 100644 --- a/os/various/chrtclib.c +++ b/os/various/chrtclib.c @@ -37,7 +37,9 @@ defined(STM32F30X) || defined(STM32F37X) || \
defined(STM32F1XX) || defined(STM32F10X_MD) || defined(STM32F10X_LD) || \
defined(STM32F10X_HD) || defined(STM32F10X_CL) || defined(STM32F0XX) || \
- defined(LPC122X) || defined(__DOXYGEN__))
+ defined(LPC122X) || defined(LPC17XX) || defined(__DOXYGEN__))
+#if STM32_RTC_IS_CALENDAR || LPC17xx_RTC_IS_CALENDAR
+
#if STM32_RTC_IS_CALENDAR
/**
* @brief Converts from STM32 BCD to canonicalized time format.
@@ -135,6 +137,47 @@ static void stm32_rtc_tm2bcd(struct tm *timp, RTCTime *timespec) { timespec->tv_time |= ((v / 10) << RTC_TR_ST_OFFSET) & RTC_TR_ST;
timespec->tv_time |= (v % 10) << RTC_TR_SU_OFFSET;
}
+#endif
+
+#if LPC17xx_RTC_IS_CALENDAR
+/**
+ * @brief Converts from LPC17xx RTC format to canonicalized time format.
+ *
+ * @param[out] timp pointer to a @p tm structure as defined in time.h
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+static void lpc17xx_rtc_format2tm(struct tm *timp, RTCTime *timespec) {
+ timp->tm_sec = timespec->sec;
+ timp->tm_min = timespec->min;
+ timp->tm_hour = timespec->hour;
+ timp->tm_mday = timespec->dom;
+ timp->tm_mon = timespec->month - 1;
+ timp->tm_year = timespec->year - 1900;
+ timp->tm_wday = timespec->dow;
+ timp->tm_yday = timespec->doy - 1;
+}
+
+/**
+ * @brief Converts from LPC17xx RTC format to canonicalized time format.
+ *
+ * @param[out] timp pointer to a @p tm structure as defined in time.h
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+static void lpc17xx_rtc_tm2format(struct tm *timp, RTCTime *timespec) {
+ timespec->sec = timp->tm_sec;
+ timespec->min = timp->tm_min;
+ timespec->hour = timp->tm_hour;
+ timespec->dom = timp->tm_mday;
+ timespec->month = timp->tm_mon + 1;
+ timespec->year = timp->tm_year + 1900;
+ timespec->dow = timp->tm_wday;
+ timespec->doy = timp->tm_yday + 1;
+}
+#endif
/**
* @brief Gets raw time from RTC and converts it to canonicalized format.
@@ -145,6 +188,7 @@ static void stm32_rtc_tm2bcd(struct tm *timp, RTCTime *timespec) { * @api
*/
void rtcGetTimeTm(RTCDriver *rtcp, struct tm *timp) {
+#if STM32_RTC_IS_CALENDAR
#if STM32_RTC_HAS_SUBSECONDS
RTCTime timespec = {0,0,FALSE,0};
#else
@@ -153,6 +197,14 @@ void rtcGetTimeTm(RTCDriver *rtcp, struct tm *timp) { rtcGetTime(rtcp, ×pec);
stm32_rtc_bcd2tm(timp, ×pec);
+#endif
+
+#if LPC17xx_RTC_IS_CALENDAR
+ RTCTime timespec;
+
+ rtcGetTime(rtcp, ×pec);
+ lpc17xx_rtc_format2tm(timp, ×pec);
+#endif
}
/**
@@ -164,6 +216,7 @@ void rtcGetTimeTm(RTCDriver *rtcp, struct tm *timp) { * @api
*/
void rtcSetTimeTm(RTCDriver *rtcp, struct tm *timp) {
+#if STM32_RTC_IS_CALENDAR
#if STM32_RTC_HAS_SUBSECONDS
RTCTime timespec = {0,0,FALSE,0};
#else
@@ -172,6 +225,14 @@ void rtcSetTimeTm(RTCDriver *rtcp, struct tm *timp) { stm32_rtc_tm2bcd(timp, ×pec);
rtcSetTime(rtcp, ×pec);
+#endif
+
+#if LPC17xx_RTC_IS_CALENDAR
+ RTCTime timespec;
+
+ lpc17xx_rtc_tm2format(timp, ×pec);
+ rtcSetTime(rtcp, ×pec);
+#endif
}
/**
@@ -183,6 +244,7 @@ void rtcSetTimeTm(RTCDriver *rtcp, struct tm *timp) { * @api
*/
time_t rtcGetTimeUnixSec(RTCDriver *rtcp) {
+#if STM32_RTC_IS_CALENDAR
#if STM32_RTC_HAS_SUBSECONDS
RTCTime timespec = {0,0,FALSE,0};
#else
@@ -194,6 +256,16 @@ time_t rtcGetTimeUnixSec(RTCDriver *rtcp) { stm32_rtc_bcd2tm(&timp, ×pec);
return mktime(&timp);
+#endif
+
+#if LPC17xx_RTC_IS_CALENDAR
+ RTCTime timespec;
+ struct tm timp;
+
+ rtcGetTime(rtcp, ×pec);
+ lpc17xx_rtc_format2tm(&timp, ×pec);
+ return mktime(&timp);
+#endif
}
/**
@@ -206,6 +278,7 @@ time_t rtcGetTimeUnixSec(RTCDriver *rtcp) { * @api
*/
void rtcSetTimeUnixSec(RTCDriver *rtcp, time_t tv_sec) {
+#if STM32_RTC_IS_CALENDAR
#if STM32_RTC_HAS_SUBSECONDS
RTCTime timespec = {0,0,FALSE,0};
#else
@@ -216,6 +289,16 @@ void rtcSetTimeUnixSec(RTCDriver *rtcp, time_t tv_sec) { localtime_r(&tv_sec, &timp);
stm32_rtc_tm2bcd(&timp, ×pec);
rtcSetTime(rtcp, ×pec);
+#endif
+
+#if LPC17xx_RTC_IS_CALENDAR
+ RTCTime timespec;
+ struct tm timp;
+
+ localtime_r(&tv_sec, &timp);
+ lpc17xx_rtc_tm2format(&timp, ×pec);
+ rtcSetTime(rtcp, ×pec);
+#endif
}
/**
@@ -354,7 +437,7 @@ uint32_t rtcGetTimeFatFromCounter(RTCDriver *rtcp) { return fattime;
}
-#endif /* STM32_RTC_IS_CALENDAR */
+#endif /* STM32_RTC_IS_CALENDAR || LPC17xx_RTC_IS_CALENDAR */
#endif /* (defined(STM32F4XX) || defined(STM32F2XX) || defined(STM32L1XX) || defined(STM32F1XX)) */
/** @} */
|