1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

Merge branch 'master' of git://github.com/elua/elua into lpc2368

This commit is contained in:
Lasitha78 2015-04-29 14:12:35 +05:30 committed by Lasitha Gunawardena
commit 68c5d964e4
45 changed files with 6026 additions and 164 deletions

View File

@ -91,4 +91,4 @@ Dado Sutter: dadosutter -at- eluaproject -dot- net
James Snyder: jbsnyder -at- eluaproject -dot- net
You are also welcomed to share your questions and suggestions on our
link:http://www.eluaproject.net/en_comunity.html#lists[Mail Discussion List]
link:http://www.eluaproject.net/get-involved/community-resources[Mail Discussion List]

26
boards/known/arm2368.lua Normal file
View File

@ -0,0 +1,26 @@
-- CP-JR ARM2368 board build configuration
-- http://www.futurlec.com/ARM2368_Controller.shtml
return {
cpu = 'lpc2368',
components = {
sercon = { uart = 0, speed = 115200, timer = 0 },
romfs = true,
shell = true,
term = { lines = 25, cols = 80 },
cints = true,
luaints = true,
linenoise = { shell_lines = 10, lua_lines = 50 },
rpc = { uart = 0, speed = 115200 },
adc = { buf_size = 4 },
xmodem = true
},
config = {
vtmr = { num = 4, freq = 4 },
ram = { ext_start = { 0x40000000 }, ext_size = { 32 * 1024 } }
},
modules = {
generic = { 'all', '-i2c', '-net', '-spi', '-can' }
}
}

View File

@ -0,0 +1,33 @@
-- LPCXpresso LPC1769 build configuration
return {
cpu = 'lpc1769',
components = {
sercon = { uart = "cdc", speed = 115200 },
romfs = true,
shell = true,
cdc = true,
term = { lines = 25, cols = 80 },
linenoise = { shell_lines = 10, lua_lines = 50 },
rpc = { uart = 0, speed = 115200 },
adc = { buf_size = 4 },
xmodem = true
},
config = {
egc = { mode = "alloc" },
ram = { internal_rams = 2 },
clocks = { external = 12000000, cpu = 120000000 },
-- P0.0 UART3 TX, P0.1 UART3 RX, P0.29 USB D+, P0.30 USB D-, P1.18 USB_UP_LED, P2.9 USB CONNECT
map_pins = {
port = { 0, 0, 0, 0, 1, 2 },
pin = { 0, 1, 29, 30, 18, 9 },
pinfunction = { 2, 2, 1, 1, 1, 1 }
}
},
modules = {
generic = { 'all', "-spi", "-i2c", "-net" },
platform = 'all',
platform_name = 'lpcxpresso'
},
}

View File

@ -15,7 +15,13 @@ return {
},
config = {
egc = { mode = "alloc" },
ram = { internal_rams = 2 }
ram = { internal_rams = 2 },
clocks = { external = 12000000, cpu = 100000000 },
map_pins = {
port = { 0, 0 },
pin = { 2, 3 },
pinfunction = { 1, 1 }
}
},
modules = {
generic = { 'all', "-spi", "-i2c", "-net" },

View File

@ -0,0 +1,31 @@
-- STM32F4-NUCLEO build configuration
return {
cpu = 'stm32f411re',
components = {
sercon = { uart = "1", speed = 115200 },
romfs = true,
cdc = false,
advanced_shell = true,
term = { lines = 25, cols = 80 },
linenoise = { shell_lines = 10, lua_lines = 50 },
stm32f4_enc = true,
rpc = { uart = "0", speed = 115200 },
adc = { buf_size = 2 },
xmodem = true,
cints = true,
luaints = true
},
config = {
egc = { mode = "alloc" },
vtmr = { num = 4, freq = 10 },
ram = { internal_rams = 1 },
clocks = { internal = 16000000, cpu = 100000000 },
stm32f4_uart_pins = { con_rx_port = 0, con_rx_pin = 3, con_tx_port = 0, con_tx_pin = 2 }
},
modules = {
generic = { 'all', "-i2c", "-net", "-can" },
platform = 'all',
},
}

View File

@ -113,6 +113,7 @@ local platform_list =
stm32 = { cpus = { 'STM32F103ZE', 'STM32F103RE' }, arch = 'cortexm' },
stm32f4 = { cpus = { 'STM32F401RE', 'STM32F407VG', 'STM32F407ZG' }, arch = 'cortexm' },
avr32 = { cpus = { 'AT32UC3A0128', 'AT32UC3A0256', 'AT32UC3A0512', 'AT32UC3B0256' }, arch = 'avr32' },
lpc23xx = { cpus = { 'LPC2368' }, arch = 'arm' },
lpc24xx = { cpus = { 'LPC2468' }, arch = 'arm' },
lpc17xx = { cpus = { 'LPC1768' }, arch = 'cortexm' }
}

View File

@ -24,6 +24,8 @@ extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
#define CON_BUF_SIZE 0
#endif // #ifndef CON_BUF_SIZE
static unsigned int skip_0A = 0;
// ****************************************************************************
// XMODEM support code
@ -55,10 +57,23 @@ static void term_out( u8 data )
static int term_in( int mode )
{
if( mode == TERM_INPUT_DONT_WAIT )
return platform_uart_recv( CON_UART_ID, CON_TIMER_ID, 0 );
else
return platform_uart_recv( CON_UART_ID, CON_TIMER_ID, PLATFORM_TIMER_INF_TIMEOUT );
int c;
do{
if( mode == TERM_INPUT_DONT_WAIT )
c = platform_uart_recv( CON_UART_ID, CON_TIMER_ID, 0 );
else
c = platform_uart_recv( CON_UART_ID, CON_TIMER_ID, PLATFORM_TIMER_INF_TIMEOUT );
// CR/LF sequence, skip the second char (LF) if applicable
if( skip_0A > 0 )
{
skip_0A=0;
if( c == 0x0A )
continue;
}
break;
}while( TRUE );
return c;
}
static int term_translate( int data )
@ -107,8 +122,11 @@ static int term_translate( int data )
}
else if( data == 0x0D )
{
// CR/LF sequence, read the second char (LF) if applicable
platform_uart_recv( CON_UART_ID, CON_TIMER_ID, TERM_TIMEOUT );
skip_0A=1;
return KC_ENTER;
}
else if( data == 0x0A )
{
return KC_ENTER;
}
else

View File

@ -131,7 +131,7 @@ static void refreshLine(const char *prompt, char *buf, size_t len, size_t pos, s
}
/* Cursor to left edge */
snprintf(seq,MAX_SEQ_LEN,"\x1b[0G");
snprintf(seq,MAX_SEQ_LEN,"\r");
term_putstr( seq, strlen( seq ) );
/* Write the prompt and the current buffer content */
term_putstr( prompt, strlen( prompt ) );
@ -140,7 +140,7 @@ static void refreshLine(const char *prompt, char *buf, size_t len, size_t pos, s
snprintf(seq,MAX_SEQ_LEN,"\x1b[0K");
term_putstr( seq, strlen( seq ) );
/* Move cursor to original position. */
snprintf(seq,MAX_SEQ_LEN,"\x1b[0G\x1b[%dC", (int)(pos+plen));
snprintf(seq,MAX_SEQ_LEN,"\r\x1b[%dC", (int)(pos+plen));
term_putstr( seq, strlen( seq ) );
}

View File

@ -2,20 +2,33 @@
-- It is used by the generic board configuration system (config/)
module( ..., package.seeall )
local at = require "attributes"
local comps = require "components"
-- Add specific components to the 'components' table
function add_platform_components( t )
function add_platform_components( t, board, cpu )
t.lpc17xx_semifs = { macro = "BUILD_SEMIFS" }
t.cdc = comps.cdc_uart()
end
-- Add specific configuration to the 'configs' table
function add_platform_configs( t )
end
-- Return an array of all the available platform modules for the given cpu
function get_platform_modules( cpu )
return {
pio = { map = "mbed_pio_map", open = "luaopen_mbed_pio" }
function add_platform_configs( t, board, cpu )
t.map_pins = {
attrs = {
port = at.array_of( at.int_attr( 'LPC17XX_MAP_PORT' )),
pin = at.array_of( at.int_attr( 'LPC17XX_MAP_PIN' )),
pinfunction = at.array_of( at.int_attr( 'LPC17XX_MAP_PINFUNCTION' ))
}
}
end
-- Return an array of all the available platform modules for the given cpu
function get_platform_modules( board, cpu )
local m = { pio = { map = "lpc17xx_pio_map", open = "luaopen_lpc17xx_pio" } }
board = board:upper()
if board == 'MBED' then
m.pio = { map = "mbed_pio_map", open = "luaopen_mbed_pio" }
end
return m
end

View File

@ -1,12 +1,22 @@
-- Configuration file for the LPC17xx backend
addi( sf( 'src/platform/%s/drivers/inc', platform ) )
addi( sf( 'src/platform/%s/usbstack/inc', platform ) )
local fwlib_files = utils.get_files( sf( "src/platform/%s/drivers/src", platform ), ".*%.c$" )
specific_files = "startup_LPC17xx.c system_LPC17xx.c core_cm3.c platform.c mbed_pio.c"
fwlib_files = fwlib_files .. " " .. utils.get_files( sf( "src/platform/%s/usbstack/src", platform ), ".*%.c$" )
specific_files = "startup_LPC17xx.c system_LPC17xx.c core_cm3.c platform.c"
local board = comp.board:upper()
if board == "MBED" then
specific_files = specific_files .. " mbed_pio.c"
else
specific_files = specific_files .. " lpc17xx_pio.c"
end
local ldscript = "LPC17xx.ld"
-- Prepend with path
specific_files = fwlib_files .. " " .. utils.prepend_path( specific_files, sf( "src/platform/%s", platform ) )
specific_files = specific_files .. " src/platform/cortex_utils.s src/platform/arm_cortex_interrupts.c"

View File

@ -17,8 +17,8 @@
#define ADC_BIT_RESOLUTION 12
// CPU frequency (needed by the CPU module, 0 if not used)
u32 mbed_get_cpu_frequency();
#define CPU_FREQUENCY mbed_get_cpu_frequency()
u32 lpc17xx_get_cpu_frequency();
#define CPU_FREQUENCY lpc17xx_get_cpu_frequency()
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX '0'

View File

@ -0,0 +1,43 @@
// eLua platform configuration
#ifndef __CPU_LPC1769_H__
#define __CPU_LPC1769_H__
#include "stacks.h"
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 5
#define NUM_SPI 0
#define NUM_UART 4
#define NUM_PWM 6
#define NUM_ADC 8
#define NUM_CAN 2
#define NUM_TIMER 4
#define ADC_BIT_RESOLUTION 12
// CPU frequency (needed by the CPU module, 0 if not used)
u32 lpc17xx_get_cpu_frequency();
#define CPU_FREQUENCY lpc17xx_get_cpu_frequency()
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX '0'
// Pins per port configuration:
// #define PIO_PINS_PER_PORT (n) if each port has the same number of pins, or
// #define PIO_PIN_ARRAY { n1, n2, ... } to define pins per port in an array
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 32
// Allocator data: define your free memory zones here in two arrays
// (start address and end address)
#define SRAM_ORIGIN 0x10000000
#define SRAM_SIZE 0x8000
#define SRAM2_ORIGIN 0x2007C000
#define SRAM2_SIZE 0x8000
#define INTERNAL_RAM1_FIRST_FREE end
#define INTERNAL_RAM1_LAST_FREE ( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 )
#define INTERNAL_RAM2_FIRST_FREE SRAM2_ORIGIN
#define INTERNAL_RAM2_LAST_FREE ( SRAM2_ORIGIN + SRAM2_SIZE - 1 )
#endif // #ifndef __CPU_LPC1769_H__

View File

@ -0,0 +1,22 @@
#ifndef __LPC17XX_USB_CDC_H
#define __LPC17XX_USB_CDC_H
#include "type.h"
#ifdef __cplusplus
extern "C"
{
#endif
int VCOM_putchar(int c);
int VCOM_getchar(void);
void platform_setup_usb_cdc(void);
#ifdef __cplusplus
}
#endif
#endif /* __LPC17XX_USB_CDC_H */

View File

@ -32,18 +32,13 @@
/* Includes ------------------------------------------------------------------- */
#include <stdint.h>
#include <type.h>
/* Public Types --------------------------------------------------------------- */
/** @defgroup LPC_Types_Public_Types
* @{
*/
/**
* @brief Boolean Type definition
*/
typedef enum {FALSE = 0, TRUE = !FALSE} Bool;
/**
* @brief Flag Status and Interrupt Flag Status type definition
*/

View File

@ -0,0 +1,462 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform_conf.h"
#ifdef BUILD_USB_CDC
#include <stdio.h>
#include <string.h> // memcpy
#include "LPC17xx.h"
#include "type.h"
#include "usbapi.h"
#include "usbdebug.h"
#ifdef CDC_BUF_SIZE
#define VCOM_FIFO_SIZE (1<<CDC_BUF_SIZE)
#else
#define VCOM_FIFO_SIZE 128
#endif
typedef struct {
int head;
int tail;
u8 *buf;
} fifo_t;
void fifo_init(fifo_t *fifo, u8 *buf)
{
fifo->head = 0;
fifo->tail = 0;
fifo->buf = buf;
}
BOOL fifo_put(fifo_t *fifo, u8 c)
{
int next;
// check if FIFO has room
next = (fifo->head + 1) % VCOM_FIFO_SIZE;
if (next == fifo->tail) {
// full
return FALSE;
}
fifo->buf[fifo->head] = c;
fifo->head = next;
return TRUE;
}
BOOL fifo_get(fifo_t *fifo, u8 *pc)
{
int next;
// check if FIFO has data
if (fifo->head == fifo->tail) {
return FALSE;
}
next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
*pc = fifo->buf[fifo->tail];
fifo->tail = next;
return TRUE;
}
int fifo_avail(fifo_t *fifo)
{
return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
}
int fifo_free(fifo_t *fifo)
{
return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
}
#define BAUD_RATE 115200
#define INT_IN_EP 0x81
#define BULK_OUT_EP 0x05
#define BULK_IN_EP 0x82
#define MAX_PACKET_SIZE 64
#define LE_WORD(x) ((x)&0xFF),((x)>>8)
// CDC definitions
#define CS_INTERFACE 0x24
#define CS_ENDPOINT 0x25
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
// data structure for GET_LINE_CODING / SET_LINE_CODING class requests
typedef struct {
u32 dwDTERate;
u8 bCharFormat;
u8 bParityType;
u8 bDataBits;
} TLineCoding;
static TLineCoding LineCoding = {115200, 0, 0, 8};
static u8 abBulkBuf[64];
static u8 abClassReqData[8];
static u8 txdata[VCOM_FIFO_SIZE];
static u8 rxdata[VCOM_FIFO_SIZE];
static fifo_t txfifo;
static fifo_t rxfifo;
// forward declaration of interrupt handler
void USBIntHandler(void);
static const u8 abDescriptors[] = {
// device descriptor
0x12,
DESC_DEVICE,
LE_WORD(0x0101), // bcdUSB
0x02, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
MAX_PACKET_SIZE0, // bMaxPacketSize
LE_WORD(0x1fc9), // idVendor
LE_WORD(0x2047), // idProduct
LE_WORD(0x0100), // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01, // bNumConfigurations
// configuration descriptor
0x09,
DESC_CONFIGURATION,
LE_WORD(67), // wTotalLength
0x02, // bNumInterfaces
0x01, // bConfigurationValue
0x00, // iConfiguration
0xC0, // bmAttributes
0x32, // bMaxPower
// control class interface
0x09,
DESC_INTERFACE,
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x01, // bNumEndPoints
0x02, // bInterfaceClass
0x02, // bInterfaceSubClass
0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
0x00, // iInterface
// header functional descriptor
0x05,
CS_INTERFACE,
0x00,
LE_WORD(0x0110),
// call management functional descriptor
0x05,
CS_INTERFACE,
0x01,
0x01, // bmCapabilities = device handles call management
0x01, // bDataInterface
// ACM functional descriptor
0x04,
CS_INTERFACE,
0x02,
0x02, // bmCapabilities
// union functional descriptor
0x05,
CS_INTERFACE,
0x06,
0x00, // bMasterInterface
0x01, // bSlaveInterface0
// notification EP
0x07,
DESC_ENDPOINT,
INT_IN_EP, // bEndpointAddress
0x03, // bmAttributes = intr
LE_WORD(8), // wMaxPacketSize
0x0A, // bInterval
// data class interface descriptor
0x09,
DESC_INTERFACE,
0x01, // bInterfaceNumber
0x00, // bAlternateSetting
0x02, // bNumEndPoints
0x0A, // bInterfaceClass = data
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface
// data EP OUT
0x07,
DESC_ENDPOINT,
BULK_OUT_EP, // bEndpointAddress
0x02, // bmAttributes = bulk
LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
0x00, // bInterval
// data EP in
0x07,
DESC_ENDPOINT,
BULK_IN_EP, // bEndpointAddress
0x02, // bmAttributes = bulk
LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
0x00, // bInterval
// string descriptors
0x04,
DESC_STRING,
LE_WORD(0x0409),
0x0E,
DESC_STRING,
'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
0x14,
DESC_STRING,
'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
0x12,
DESC_STRING,
'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
// terminating zero
0
};
/**
Local function to handle incoming bulk data
@param [in] bEP
@param [in] bEPStatus
*/
static void BulkOut(u8 bEP, u8 bEPStatus)
{
int i, iLen;
if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) {
// may not fit into fifo
return;
}
// get data from USB into intermediate buffer
iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));
for (i = 0; i < iLen; i++) {
// put into FIFO
if (!fifo_put(&rxfifo, abBulkBuf[i])) {
// overflow... :(
ASSERT(FALSE);
break;
}
}
}
/**
Local function to handle outgoing bulk data
@param [in] bEP
@param [in] bEPStatus
*/
static void BulkIn(u8 bEP, u8 bEPStatus)
{
int i, iLen;
if (fifo_avail(&txfifo) == 0) {
// no more data, disable further NAK interrupts until next USB frame
USBHwNakIntEnable(0);
return;
}
// get bytes from transmit FIFO into intermediate buffer
for (i = 0; i < MAX_PACKET_SIZE; i++) {
if (!fifo_get(&txfifo, &abBulkBuf[i])) {
break;
}
}
iLen = i;
// send over USB
if (iLen > 0) {
USBHwEPWrite(bEP, abBulkBuf, iLen);
}
}
/**
Local function to handle the USB-CDC class requests
@param [in] pSetup
@param [out] piLen
@param [out] ppbData
*/
static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
switch (pSetup->bRequest) {
// set line coding
case SET_LINE_CODING:
DBG("SET_LINE_CODING\n");
memcpy((u8 *)&LineCoding, *ppbData, 7);
*piLen = 7;
DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n",
LineCoding.dwDTERate,
LineCoding.bCharFormat,
LineCoding.bParityType,
LineCoding.bDataBits);
break;
// get line coding
case GET_LINE_CODING:
DBG("GET_LINE_CODING\n");
*ppbData = (u8 *)&LineCoding;
*piLen = 7;
break;
// set control line state
case SET_CONTROL_LINE_STATE:
// bit0 = DTR, bit = RTS
DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue);
break;
default:
return FALSE;
}
return TRUE;
}
/**
Initialises the VCOM port.
Call this function before using VCOM_putchar or VCOM_getchar
*/
void VCOM_init(void)
{
fifo_init(&txfifo, txdata);
fifo_init(&rxfifo, rxdata);
}
/**
Writes one character to VCOM port
@param [in] c character to write
@returns character written, or EOF if character could not be written
*/
int VCOM_putchar(int c)
{
return fifo_put(&txfifo, c) ? c : EOF;
}
/**
Reads one character from VCOM port
@returns character read, or EOF if character could not be read
*/
int VCOM_getchar(void)
{
u8 c;
return fifo_get(&rxfifo, &c) ? c : EOF;
}
/**
Interrupt handler
Simply calls the USB ISR
This gets installed by overriding a WEAK linker symbol
*/
void USB_IRQHandler(void)
{
USBHwISR();
}
static void USBFrameHandler(u16 wFrame)
{
if (fifo_avail(&txfifo) > 0) {
// data available, enable NAK interrupt on bulk in
USBHwNakIntEnable(INACK_BI);
}
}
void platform_setup_usb_cdc(void)
{
int c;
printf("Initialising USB stack\n");
// initialise stack
USBInit();
// register descriptors
USBRegisterDescriptors(abDescriptors);
// register class request handler
USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
// register endpoint handlers
USBHwRegisterEPIntHandler(INT_IN_EP, NULL);
USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);
USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);
// register frame handler
USBHwRegisterFrameHandler(USBFrameHandler);
// enable bulk-in interrupts on NAKs
USBHwNakIntEnable(INACK_BI);
// initialise VCOM
VCOM_init();
printf("Starting USB communication\n");
// enable IRQ
NVIC_EnableIRQ(USB_IRQn);
// connect to bus
printf("Connecting to USB bus\n");
USBHwConnect(TRUE);
}
#endif

View File

@ -0,0 +1,79 @@
// LPC17xx specific PIO support
#include <string.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "lrotable.h"
#include "platform_conf.h"
#include "auxmods.h"
#include "lpc17xx_pinsel.h"
static int configpin( lua_State* L )
{
pio_type v = ( pio_type )luaL_checkinteger( L, 1 );
int funcnum = luaL_checkinteger( L, 2 );
int opendrain = luaL_checkinteger( L, 3 );
int pinmode = luaL_checkinteger( L, 4 );
PINSEL_CFG_Type PinCfg;
int port, pin;
port = PLATFORM_IO_GET_PORT( v );
pin = PLATFORM_IO_GET_PIN( v );
if( PLATFORM_IO_IS_PORT( v ) || !platform_pio_has_port( port ) || !platform_pio_has_pin( port, pin ) )
return luaL_error( L, "invalid pin" );
PinCfg.Funcnum = funcnum;
PinCfg.OpenDrain = opendrain;
PinCfg.Pinmode = pinmode;
PinCfg.Portnum = port;
PinCfg.Pinnum = pin;
PINSEL_ConfigPin(&PinCfg);
return 0;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE lpc17xx_pio_map[] =
{
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__metatable" ), LROVAL( lpc17xx_pio_map ) },
{ LSTRKEY( "RES_PULLUP" ), LNUMVAL( PINSEL_PINMODE_PULLUP )},
{ LSTRKEY( "RES_TRISTATE" ), LNUMVAL( PINSEL_PINMODE_TRISTATE )},
{ LSTRKEY( "RES_PULLDOWN" ), LNUMVAL( PINSEL_PINMODE_PULLDOWN )},
{ LSTRKEY( "FUNCTION_0" ), LNUMVAL( PINSEL_FUNC_0 )},
{ LSTRKEY( "FUNCTION_1" ), LNUMVAL( PINSEL_FUNC_1 )},
{ LSTRKEY( "FUNCTION_2" ), LNUMVAL( PINSEL_FUNC_2 )},
{ LSTRKEY( "FUNCTION_3" ), LNUMVAL( PINSEL_FUNC_3 )},
{ LSTRKEY( "MODE_DEFAULT" ), LNUMVAL( PINSEL_PINMODE_NORMAL )},
{ LSTRKEY( "MODE_OD" ), LNUMVAL( PINSEL_PINMODE_OPENDRAIN )},
#endif
{ LSTRKEY( "configpin" ), LFUNCVAL( configpin ) },
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_lpc17xx_pio( lua_State *L )
{
#if LUA_OPTIMIZE_MEMORY > 0
return 0;
#else
luaL_register( L, PS_LIB_TABLE_NAME, lpc17xx_pio_map );
MOD_REG_NUMBER( L, "RES_PULLUP", PINSEL_PINMODE_PULLUP );
MOD_REG_NUMBER( L, "RES_TRISTATE", PINSEL_PINMODE_TRISTATE );
MOD_REG_NUMBER( L, "RES_PULLDOWN", PINSEL_PINMODE_PULLDOWN );
MOD_REG_NUMBER( L, "FUNCTION_0", PINSEL_FUNC_0 );
MOD_REG_NUMBER( L, "FUNCTION_1", PINSEL_FUNC_1 );
MOD_REG_NUMBER( L, "FUNCTION_2", PINSEL_FUNC_2 );
MOD_REG_NUMBER( L, "FUNCTION_3", PINSEL_FUNC_3 );
MOD_REG_NUMBER( L, "MODE_DEFAULT", PINSEL_PINMODE_NORMAL );
MOD_REG_NUMBER( L, "MODE_OD", PINSEL_PINMODE_OPENDRAIN );
// Set it as its own metatable
lua_pushvalue( L, -1 );
lua_setmetatable( L, -2 );
return 1;
#endif
}

View File

@ -28,6 +28,7 @@
#include "lpc17xx_pwm.h"
#include "lpc17xx_adc.h"
#include "lpc17xx_can.h"
#include "lpc17xx_usb_cdc.h"
#define SYSTICKHZ 10
@ -38,12 +39,13 @@ static void platform_setup_timers();
static void platform_setup_pwm();
static void platform_setup_adcs();
static void cans_init( void );
static void platform_setup_pins();
int platform_init()
{
// Set up microcontroller system and SystemCoreClock variable
SystemInit();
// DeInit NVIC and SCBNVIC
NVIC_DeInit();
NVIC_SCBDeInit();
@ -73,21 +75,29 @@ int platform_init()
// Setup CANs
cans_init();
// Setup pin routing
platform_setup_pins();
// System timer setup
cmn_systimer_set_base_freq( mbed_get_cpu_frequency() );
cmn_systimer_set_base_freq( lpc17xx_get_cpu_frequency() );
cmn_systimer_set_interrupt_freq( SYSTICKHZ );
// Enable SysTick
SysTick_Config( mbed_get_cpu_frequency() / SYSTICKHZ );
SysTick_Config( lpc17xx_get_cpu_frequency() / SYSTICKHZ );
#ifdef BUILD_USB_CDC
// Setup USB CDC
platform_setup_usb_cdc();
#endif
// Common platform initialization code
cmn_platform_init();
return PLATFORM_OK;
}
}
extern u32 SystemCoreClock;
u32 mbed_get_cpu_frequency()
u32 lpc17xx_get_cpu_frequency()
{
return SystemCoreClock;
}
@ -104,50 +114,71 @@ void SysTick_Handler()
// ****************************************************************************
// PIO section
static const u8 map_ports[] = LPC17XX_MAP_PORT;
static const u8 map_pins [] = LPC17XX_MAP_PIN;
static const u8 map_funcs[] = LPC17XX_MAP_PINFUNCTION;
static void platform_setup_pins(void)
{
PINSEL_CFG_Type PinCfg;
u8 i;
PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
PinCfg.Pinmode = PINSEL_PINMODE_PULLUP;
for(i=0; i<sizeof(map_ports); i++)
{
PinCfg.Portnum = map_ports[i];
PinCfg.Pinnum = map_pins [i];
PinCfg.Funcnum = map_funcs[i];
PINSEL_ConfigPin(&PinCfg);
}
}
// The platform I/O functions
pio_type platform_pio_op( unsigned port, pio_type pinmask, int op )
{
pio_type retval = 1;
switch( op )
{
case PLATFORM_IO_PORT_SET_VALUE:
case PLATFORM_IO_PORT_SET_VALUE:
GPIO_SetValue(port, pinmask);
break;
case PLATFORM_IO_PIN_SET:
GPIO_SetValue(port, pinmask);
break;
case PLATFORM_IO_PIN_CLEAR:
GPIO_ClearValue(port, pinmask);
break;
case PLATFORM_IO_PORT_DIR_OUTPUT:
GPIO_SetDir(port, 0xFFFFFFFF, 1);
break;
break;
case PLATFORM_IO_PIN_DIR_OUTPUT:
GPIO_SetDir(port, pinmask, 1);
break;
case PLATFORM_IO_PORT_DIR_INPUT:
GPIO_SetDir(port, 0xFFFFFFFF, 0);
break;
case PLATFORM_IO_PIN_DIR_INPUT:
GPIO_SetDir(port, pinmask, 0);
break;
break;
case PLATFORM_IO_PORT_GET_VALUE:
retval = GPIO_ReadValue(port);
break;
case PLATFORM_IO_PIN_GET:
retval = ( GPIO_ReadValue(port) & pinmask ) ? 1 : 0;
break;
default:
retval = 0;
break;
@ -159,9 +190,8 @@ pio_type platform_pio_op( unsigned port, pio_type pinmask, int op )
// ****************************************************************************
// UART section
// UART0: Rx = P0.3, Tx = P0.2
// The other UARTs have assignable Rx/Tx pins and thus have to be configured
// by the user
// If you want to use an UART, make sure it is routed to your desired output
// pin. See section 8.5 of the LPC17xx User Manual.
static LPC_UART_TypeDef* const uart[] = { LPC_UART0, LPC_UART1, LPC_UART2, LPC_UART3 };
@ -171,27 +201,20 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
UART_CFG_Type UARTConfigStruct;
// UART FIFO configuration Struct variable
UART_FIFO_CFG_Type UARTFIFOConfigStruct;
// Pin configuration for UART0
PINSEL_CFG_Type PinCfg;
// UART0 Pin Config
PinCfg.Funcnum = 1;
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = 0;
PinCfg.Pinnum = 2;
PinCfg.Portnum = 0;
PINSEL_ConfigPin(&PinCfg);
PinCfg.Pinnum = 3;
PINSEL_ConfigPin(&PinCfg);
UARTConfigStruct.Baud_rate = ( uint32_t )baud;
#ifdef BUILD_USB_CDC
if( id == CDC_UART_ID )
return 0;
#endif
switch( databits )
{
case 5:
UARTConfigStruct.Databits = UART_DATABIT_5;
break;
case 6:
UARTConfigStruct.Databits = UART_DATABIT_6;
break;
@ -204,33 +227,33 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
UARTConfigStruct.Databits = UART_DATABIT_8;
break;
}
if( stopbits == PLATFORM_UART_STOPBITS_2 )
UARTConfigStruct.Stopbits = UART_STOPBIT_2;
else
UARTConfigStruct.Stopbits = UART_STOPBIT_1;
switch( parity )
{
case PLATFORM_UART_PARITY_NONE:
UARTConfigStruct.Parity = UART_PARITY_NONE;
break;
case PLATFORM_UART_PARITY_ODD:
UARTConfigStruct.Parity = UART_PARITY_ODD;
break;
case PLATFORM_UART_PARITY_EVEN:
UARTConfigStruct.Parity = UART_PARITY_EVEN;
break;
case PLATFORM_UART_PARITY_MARK:
UARTConfigStruct.Parity = UART_PARITY_SP_1;
break;
case PLATFORM_UART_PARITY_SPACE:
UARTConfigStruct.Parity = UART_PARITY_SP_0;
break;
break;
}
UART_Init(uart[ id ], &UARTConfigStruct);
@ -238,22 +261,44 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
// Get default FIFO config and initialize
UART_FIFOConfigStructInit(&UARTFIFOConfigStruct);
UART_FIFOConfig(uart[ id ], &UARTFIFOConfigStruct);
// Enable Transmit
UART_TxCmd(uart[ id ], ENABLE);
return baud; // FIXME: find a way to actually get baud
}
void platform_s_uart_send( unsigned id, u8 data )
{
UART_Send(uart[ id ], &data, 1, BLOCKING);
#ifdef BUILD_USB_CDC
if( id == CDC_UART_ID )
VCOM_putchar( data );
else
#endif
{
UART_Send(uart[ id ], &data, 1, BLOCKING);
}
}
int platform_s_uart_recv( unsigned id, timer_data_type timeout )
{
u8 buffer;
int rc;
/* Polling is bad style. Replace me with something interrupt-driven. */
#ifdef BUILD_USB_CDC
if( id == CDC_UART_ID )
{
do
{
rc = VCOM_getchar();
if( (timeout == 0) && (rc == EOF) )
return -1;
} while( rc == EOF );
return rc;
}
#endif
if( timeout == 0 )
{
if ( UART_Receive(uart[ id ], &buffer, 1, NONE_BLOCKING) == 0 )
@ -261,7 +306,7 @@ int platform_s_uart_recv( unsigned id, timer_data_type timeout )
else
return ( int )buffer;
}
UART_Receive(uart[ id ], &buffer, 1, BLOCKING);
return ( int )buffer;
}
@ -297,7 +342,7 @@ static u32 platform_timer_set_clock( unsigned id, u32 clock )
TIM_Init( tmr[ id ], TIM_TIMER_MODE, &TIM_ConfigStruct );
TIM_Cmd( tmr[ id ], ENABLE );
TIM_ResetCounter( tmr[ id ] );
return clock;
}
@ -305,11 +350,11 @@ static u32 platform_timer_set_clock( unsigned id, u32 clock )
static void platform_setup_timers()
{
unsigned i;
// Power on clocks on APB1
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM2, ENABLE);
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM3, ENABLE);
// Set base frequency to 1MHz, as we can't use a better resolution anyway
for( i = 0; i < 4; i ++ )
platform_timer_set_clock( i, 1000000ULL );
@ -324,7 +369,7 @@ void platform_s_timer_delay( unsigned id, timer_data_type delay_us )
TIM_ResetCounter( tmr[ id ] );
while( tmr[ id ]->TC < last );
}
timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
{
u32 res = 0;
@ -335,7 +380,7 @@ timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
TIM_Cmd( tmr[ id ], ENABLE );
TIM_ResetCounter( tmr[ id ] );
break;
case PLATFORM_TIMER_OP_READ:
res = tmr[ id ]->TC;
break;
@ -343,7 +388,7 @@ timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
case PLATFORM_TIMER_OP_SET_CLOCK:
res = platform_timer_set_clock( id, data );
break;
case PLATFORM_TIMER_OP_GET_CLOCK:
res = platform_timer_get_clock( id );
break;
@ -390,13 +435,13 @@ int platform_adc_check_timer_id( unsigned id, unsigned timer_id )
}
void platform_adc_stop( unsigned id )
{
{
elua_adc_ch_state *s = adc_get_ch_state( id );
elua_adc_dev_state *d = adc_get_dev_state( 0 );
s->op_pending = 0;
INACTIVATE_CHANNEL( d, id );
// If there are no more active channels, stop the sequencer
if( d->ch_active == 0 && d->running == 1 )
{
@ -412,17 +457,17 @@ void ADC_IRQHandler(void)
elua_adc_dev_state *d = adc_get_dev_state( 0 );
elua_adc_ch_state *s = d->ch_state[ d->seq_ctr ];
//int i;
// Disable sampling & current sequence channel
ADC_StartCmd( LPC_ADC, 0 );
ADC_ChannelCmd( LPC_ADC, s->id, DISABLE );
ADC_IntConfig( LPC_ADC, s->id, DISABLE );
if ( ADC_ChannelGetStatus( LPC_ADC, s->id, ADC_DATA_DONE ) )
{
{
d->sample_buf[ d->seq_ctr ] = ( u16 )ADC_ChannelGetData( LPC_ADC, s->id );
s->value_fresh = 1;
if ( s->logsmoothlen > 0 && s->smooth_ready == 0)
adc_smooth_data( s->id );
#if defined( BUF_ENABLE_ADC )
@ -432,11 +477,11 @@ void ADC_IRQHandler(void)
s->value_fresh = 0;
}
#endif
if ( adc_samples_available( s->id ) >= s->reqsamples && s->freerunning == 0 )
platform_adc_stop( s->id );
platform_adc_stop( s->id );
}
// Set up for next channel acquisition if we're still running
if( d->running == 1 )
{
@ -444,14 +489,14 @@ void ADC_IRQHandler(void)
if( d->seq_ctr < ( d->seq_len - 1 ) )
d->seq_ctr++;
else if( d->seq_ctr == ( d->seq_len - 1 ) )
{
{
adc_update_dev_sequence( 0 );
d->seq_ctr = 0; // reset sequence counter if on last sequence entry
}
ADC_ChannelCmd( LPC_ADC, d->ch_state[ d->seq_ctr ]->id, ENABLE );
ADC_IntConfig( LPC_ADC, d->ch_state[ d->seq_ctr ]->id, ENABLE );
if( d->clocked == 1 && d->seq_ctr == 0 ) // always use clock for first in clocked sequence
ADC_StartCmd( LPC_ADC, adc_trig[ d->timer_id ] );
@ -465,20 +510,20 @@ void ADC_IRQHandler(void)
static void platform_setup_adcs()
{
unsigned id;
for( id = 0; id < NUM_ADC; id ++ )
adc_init_ch_state( id );
NVIC_SetPriority(ADC_IRQn, ((0x01<<3)|0x01));
ADC_Init(LPC_ADC, 13000000);
// Default enables CH0, disable channel
ADC_ChannelCmd( LPC_ADC, 0, DISABLE );
// Default enables ADC interrupt only on global, switch to per-channel
ADC_IntConfig( LPC_ADC, ADC_ADGINTEN, DISABLE );
platform_adc_set_clock( 0, 0 );
}
@ -493,15 +538,15 @@ u32 platform_adc_set_clock( unsigned id, u32 frequency )
if ( frequency > 0 )
{
d->clocked = 1;
// Max Sampling Rate on LPC1768 is 200 kS/s
if ( frequency > 200000 )
frequency = 200000;
// Run timer at 1MHz
TIM_ConfigStruct.PrescaleOption = TIM_PRESCALE_USVAL;
TIM_ConfigStruct.PrescaleValue = 1;
TIM_MatchConfigStruct.MatchChannel = 1;
TIM_MatchConfigStruct.IntOnMatch = FALSE;
TIM_MatchConfigStruct.ResetOnMatch = TRUE;
@ -509,9 +554,9 @@ u32 platform_adc_set_clock( unsigned id, u32 frequency )
TIM_MatchConfigStruct.ExtMatchOutputType = TIM_EXTMATCH_TOGGLE;
// Set match value to period (in uS) associated with frequency
TIM_MatchConfigStruct.MatchValue = ( 1000000ULL / ( frequency * 2 ) ) - 1;
frequency = 1000000ULL / (TIM_MatchConfigStruct.MatchValue + 1);
// Set configuration for Tim_config and Tim_MatchConfig
TIM_Init( tmr[ d->timer_id ], TIM_TIMER_MODE, &TIM_ConfigStruct );
TIM_ConfigMatch( tmr[ d->timer_id ], &TIM_MatchConfigStruct );
@ -519,48 +564,48 @@ u32 platform_adc_set_clock( unsigned id, u32 frequency )
}
else
d->clocked = 0;
return frequency;
}
static const u8 adc_ports[] = { 0, 0, 0, 0, 1, 1, 0, 0 };
static const u8 adc_pins[] = { 23, 24, 25, 26, 30, 31, 3, 2 };
static const u8 adc_pins[] = { 23, 24, 25, 26, 30, 31, 3, 2 };
static const u8 adc_funcs[] = { 1, 1, 1, 1, 3, 3, 2, 2 };
// Prepare Hardware Channel
int platform_adc_update_sequence( )
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
PINSEL_CFG_Type PinCfg;
u8 seq_tmp;
unsigned id;
// Enable Needed Pins
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = 0;
for( seq_tmp = 0; seq_tmp < d->seq_len; seq_tmp++ )
{
id = d->ch_state[ seq_tmp ]->id;
PinCfg.Funcnum = adc_funcs[ id ];
PinCfg.Pinnum = adc_pins[ id ];
PinCfg.Pinnum = adc_pins[ id ];
PinCfg.Portnum = adc_ports[ id ];
PINSEL_ConfigPin(&PinCfg);
}
return PLATFORM_OK;
}
int platform_adc_start_sequence()
{
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
if( d->running != 1 )
{
adc_update_dev_sequence( 0 );
// Start sampling on first channel
d->seq_ctr = 0;
ADC_ChannelCmd( LPC_ADC, d->ch_state[ d->seq_ctr ]->id, ENABLE );
@ -568,7 +613,7 @@ int platform_adc_start_sequence()
d->running = 1;
NVIC_EnableIRQ( ADC_IRQn );
if( d->clocked == 1 )
{
ADC_StartCmd( LPC_ADC, adc_trig[ d->timer_id ] );
@ -578,7 +623,7 @@ int platform_adc_start_sequence()
else
ADC_StartCmd( LPC_ADC, ADC_START_NOW );
}
return PLATFORM_OK;
}
@ -599,7 +644,7 @@ u32 platform_pwm_get_clock( unsigned id )
u32 platform_pwm_set_clock( unsigned id, u32 clock )
{
PWM_TIMERCFG_Type PWMCfgDat;
PWMCfgDat.PrescaleOption = PWM_TIMER_PRESCALE_USVAL;
PWMCfgDat.PrescaleValue = 1000000ULL / clock;
PWM_Init( LPC_PWM1, PWM_MODE_TIMER, &PWMCfgDat );
@ -611,10 +656,10 @@ u32 platform_pwm_set_clock( unsigned id, u32 clock )
static void platform_setup_pwm()
{
PWM_MATCHCFG_Type PWMMatchCfgDat;
// Keep clock in reset, set PWM code
PWM_ResetCounter( LPC_PWM1 );
// Set match mode (reset on MR0 match)
PWMMatchCfgDat.IntOnMatch = DISABLE;
PWMMatchCfgDat.MatchChannel = 0;
@ -630,13 +675,13 @@ u32 platform_pwm_setup( unsigned id, u32 frequency, unsigned duty )
{
PWM_MATCHCFG_Type PWMMatchCfgDat;
u32 divisor = platform_pwm_get_clock( id ) / frequency - 1;
PWM_MatchUpdate( LPC_PWM1, 0, divisor, PWM_MATCH_UPDATE_NOW ); // PWM1 cycle rate
PWM_MatchUpdate( LPC_PWM1, id, ( divisor * duty ) / 100, PWM_MATCH_UPDATE_NOW ); // PWM1 channel edge position
if ( id > 1 ) // Channel one is permanently single-edge
PWM_ChannelConfig( LPC_PWM1, id, PWM_CHANNEL_SINGLE_EDGE );
PWMMatchCfgDat.IntOnMatch = DISABLE;
PWMMatchCfgDat.MatchChannel = id;
PWMMatchCfgDat.ResetOnMatch = DISABLE;
@ -673,7 +718,7 @@ void CAN_IRQHandler(void)
// CAN1 Error (bits 1~10 cleared when read)
if (LPC_CAN1->ICR & (1<<2 | 1<<5 | 1<<7))
can_err_flag[0] = 1;
// CAN1 Receive
if (LPC_CAN1->ICR & (1<<0))
{
@ -701,7 +746,7 @@ void cans_init( void )
u32 platform_can_setup( unsigned id, u32 clock )
{
{
LPC_CAN_TypeDef * canx;
uint32_t div;
@ -712,13 +757,13 @@ u32 platform_can_setup( unsigned id, u32 clock )
default: return 0;
}
CAN_DeInit(canx);
CAN_DeInit(canx);
CAN_Init(canx, clock);
CAN_ModeConfig(canx, CAN_OPERATING_MODE, ENABLE);
CAN_IRQCmd(canx, CANINT_RIE, ENABLE); // Receive IRQ
CAN_IRQCmd(canx, CANINT_EIE, ENABLE); // Error IRQ
CAN_IRQCmd(canx, CANINT_BEIE, ENABLE); // Bus error IRQ
LPC_CANAF->AFMR = 2; // Filter bypass (receive all messages)
CAN_ModeConfig(canx, CAN_OPERATING_MODE, ENABLE);
CAN_IRQCmd(canx, CANINT_RIE, ENABLE); // Receive IRQ
CAN_IRQCmd(canx, CANINT_EIE, ENABLE); // Error IRQ
CAN_IRQCmd(canx, CANINT_BEIE, ENABLE); // Bus error IRQ
LPC_CANAF->AFMR = 2; // Filter bypass (receive all messages)
NVIC_EnableIRQ(CAN_IRQn); // Enable IRQs
// Fix clock
@ -800,7 +845,7 @@ int platform_can_recv( unsigned id, u32 *canid, u8 *idtype, u8 *len, u8 *data )
if( can_rx_flag[id] != 0 )
{
memcpy(data, &(can_msg_rx[id].dataA), 4);
memcpy(data+4, &(can_msg_rx[id].dataB), 4);
memcpy(data+4, &(can_msg_rx[id].dataB), 4);
can_rx_flag[id] = 0;
@ -813,4 +858,3 @@ int platform_can_recv( unsigned id, u32 *canid, u8 *idtype, u8 *len, u8 *data )
else
return PLATFORM_UNDERFLOW;
}

View File

@ -20,15 +20,15 @@
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
* @par
* Modified for usage in eLua.
*
******************************************************************************/
#include <stdint.h>
#include "LPC17xx.h"
/*
//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
*/
#include <platform_conf.h>
/*--------------------- Clock Configuration ----------------------------------
//
@ -279,23 +279,6 @@
// </h>
//
// </e>
*/
#define CLOCK_SETUP 1
#define SCS_Val 0x00000020
#define CLKSRCSEL_Val 0x00000001
#define PLL0_SETUP 1
#define PLL0CFG_Val 0x00050063
#define PLL1_SETUP 1
#define PLL1CFG_Val 0x00000023
#define CCLKCFG_Val 0x00000003
#define USBCLKCFG_Val 0x00000000
#define PCLKSEL0_Val 0x00000000
#define PCLKSEL1_Val 0x00000000
#define PCONP_Val 0x042887DE
#define CLKOUTCFG_Val 0x00000000
/*--------------------- Flash Accelerator Configuration ----------------------
//
// <e> Flash Accelerator Configuration
// <o1.0..11> Reserved
@ -304,12 +287,43 @@
// <1=> 2 CPU clocks (for CPU clock up to 40 MHz)
// <2=> 3 CPU clocks (for CPU clock up to 60 MHz)
// <3=> 4 CPU clocks (for CPU clock up to 80 MHz)
// <4=> 5 CPU clocks (for CPU clock up to 100 MHz)
// <4=> 5 CPU clocks (for CPU clock up to 100 MHz, or 1769 up to 120MHz)
// <5=> 6 CPU clocks (for any CPU clock)
// </e>
*/
/*----------------------------------------------------------------------------
Define clocks
*----------------------------------------------------------------------------*/
#define XTAL ((DWORD)(ELUA_BOARD_EXTERNAL_CLOCK_HZ)) /* Oscillator frequency */
#define OSC_CLK ((DWORD)( XTAL)) /* Main oscillator frequency */
#define RTC_CLK ((DWORD)( 32768UL)) /* RTC oscillator frequency */
#define IRC_OSC ((DWORD)( 4000000UL)) /* Internal RC oscillator frequency */
#define CPU_CLK ( ELUA_BOARD_CPU_CLOCK_HZ) /* Desired CPU clock */
#define CLOCK_SETUP 1
#define SCS_Val 0x00000020
#define CLKSRCSEL_Val 0x00000001
#define PLL0_SETUP 1
/* In a perfect world, we'd calculate the PLL configuration from the information above.
* For now, just handle the two cases we actually know about. */
#if CPU_CLK==100000000
#define PLL0CFG_Val 0x00050063
#elif CPU_CLK==120000000
#define PLL0CFG_Val 0x00050077
#else
#error "Unsupported CPU clock, please provide PLL configuration"
#endif
#define PLL1_SETUP 1
#define PLL1CFG_Val 0x00000023
#define CCLKCFG_Val 0x00000003
#define USBCLKCFG_Val 0x00000000
#define PCLKSEL0_Val 0x00000000
#define PCLKSEL1_Val 0x00000000
#define PCONP_Val 0x042887DE
#define CLKOUTCFG_Val 0x00000000
#define FLASH_SETUP 1
#define FLASHCFG_Val 0x0000303A
#define FLASHCFG_Val 0x0000403A
/*
//-------- <<< end of configuration section >>> ------------------------------
@ -372,15 +386,6 @@
DEFINES
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Define clocks
*----------------------------------------------------------------------------*/
#define XTAL (12000000UL) /* Oscillator frequency */
#define OSC_CLK ( XTAL) /* Main oscillator frequency */
#define RTC_CLK ( 32000UL) /* RTC oscillator frequency */
#define IRC_OSC ( 4000000UL) /* Internal RC oscillator frequency */
/* F_cco0 = (2 * M * F_in) / N */
#define __M (((PLL0CFG_Val ) & 0x7FFF) + 1)
#define __N (((PLL0CFG_Val >> 16) & 0x00FF) + 1)

View File

@ -1,6 +1,19 @@
#ifndef __TYPE_H__
#define __TYPE_H__
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
@ -16,6 +29,7 @@ typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned int BOOL;
typedef unsigned int Bool;
typedef volatile unsigned long* PREG;

View File

@ -0,0 +1,120 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@file
*/
#include "type.h"
#include "usbstruct.h" // for TSetupPacket
/*************************************************************************
USB configuration
**************************************************************************/
#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */
/*************************************************************************
USB hardware interface
**************************************************************************/
// endpoint status sent through callback
#define EP_STATUS_DATA (1<<0) /**< EP has data */
#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */
#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */
#define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */
#define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */
// device status sent through callback
#define DEV_STATUS_CONNECT (1<<0) /**< device just got connected */
#define DEV_STATUS_SUSPEND (1<<2) /**< device entered suspend state */
#define DEV_STATUS_RESET (1<<4) /**< device just got reset */
// interrupt bits for NACK events in USBHwNakIntEnable
// (these bits conveniently coincide with the LPC176x USB controller bit)
#define INACK_CI (1<<1) /**< interrupt on NACK for control in */
#define INACK_CO (1<<2) /**< interrupt on NACK for control out */
#define INACK_II (1<<3) /**< interrupt on NACK for interrupt in */
#define INACK_IO (1<<4) /**< interrupt on NACK for interrupt out */
#define INACK_BI (1<<5) /**< interrupt on NACK for bulk in */
#define INACK_BO (1<<6) /**< interrupt on NACK for bulk out */
BOOL USBHwInit (void);
void USBHwISR (void);
void USBHwNakIntEnable (u8 bIntBits);
void USBHwConnect (BOOL fConnect);
void USBHwSetAddress (u8 bAddr);
void USBHwConfigDevice (BOOL fConfigured);
// endpoint operations
void USBHwEPConfig (u8 bEP, u16 wMaxPacketSize);
int USBHwEPRead (u8 bEP, u8 *pbBuf, int iMaxLen);
int USBHwEPWrite (u8 bEP, u8 *pbBuf, int iLen);
void USBHwEPStall (u8 bEP, BOOL fStall);
u8 USBHwEPGetStatus (u8 bEP);
/** Endpoint interrupt handler callback */
typedef void (TFnEPIntHandler) (u8 bEP, u8 bEPStatus);
void USBHwRegisterEPIntHandler (u8 bEP, TFnEPIntHandler *pfnHandler);
/** Device status handler callback */
typedef void (TFnDevIntHandler) (u8 bDevStatus);
void USBHwRegisterDevIntHandler (TFnDevIntHandler *pfnHandler);
/** Frame event handler callback */
typedef void (TFnFrameHandler)(u16 wFrame);
void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler);
/*************************************************************************
USB application interface
**************************************************************************/
// initialise the complete stack, including HW
BOOL USBInit(void);
/** Request handler callback (standard, vendor, class) */
typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, u8 **ppbData);
void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, u8 *pbDataStore);
void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler);
/** Descriptor handler callback */
typedef BOOL (TFnGetDescriptor)(u16 wTypeIndex, u16 wLangID, int *piLen, u8 **ppbData);
/** Default standard request handler */
BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, u8 **ppbData);
/** Default EP0 handler */
void USBHandleControlTransfer(u8 bEP, u8 bEPStat);
/** Descriptor handling */
void USBRegisterDescriptors(const u8 *pabDescriptors);
BOOL USBGetDescriptor(u16 wTypeIndex, u16 wLangID, int *piLen, u8 **ppbData);

View File

@ -0,0 +1,36 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
# include <stdio.h>
#ifdef DEBUG_MESSAGES
#define DBG printf
#define ASSERT(x) if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);}
#else
#define DBG(x ...)
#define ASSERT(x)
#endif

View File

@ -0,0 +1,140 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
Hardware definitions for the LPC176x USB controller
These are private to the usbhw module
*/
// CodeRed - pull in defines from NXP header file
#include "LPC17xx.h"
// CodeRed - these registers have been renamed on LPC176x
#define USBReEP USBReEp
#define OTG_CLK_CTRL USBClkCtrl
#define OTG_CLK_STAT USBClkSt
/* USBIntSt bits */
#define USB_INT_REQ_LP (1<<0)
#define USB_INT_REQ_HP (1<<1)
#define USB_INT_REQ_DMA (1<<2)
#define USB_need_clock (1<<8)
#define EN_USB_BITS (1<<31)
/* USBDevInt... bits */
#define FRAME (1<<0)
#define EP_FAST (1<<1)
#define EP_SLOW (1<<2)
#define DEV_STAT (1<<3)
#define CCEMTY (1<<4)
#define CDFULL (1<<5)
#define RxENDPKT (1<<6)
#define TxENDPKT (1<<7)
#define EP_RLZED (1<<8)
#define ERR_INT (1<<9)
/* USBRxPLen bits */
#define PKT_LNGTH (1<<0)
#define PKT_LNGTH_MASK 0x3FF
#define DV (1<<10)
#define PKT_RDY (1<<11)
/* USBCtrl bits */
#define RD_EN (1<<0)
#define WR_EN (1<<1)
#define LOG_ENDPOINT (1<<2)
/* protocol engine command codes */
/* device commands */
#define CMD_DEV_SET_ADDRESS 0xD0
#define CMD_DEV_CONFIG 0xD8
#define CMD_DEV_SET_MODE 0xF3
#define CMD_DEV_READ_CUR_FRAME_NR 0xF5
#define CMD_DEV_READ_TEST_REG 0xFD
#define CMD_DEV_STATUS 0xFE /* read/write */
#define CMD_DEV_GET_ERROR_CODE 0xFF
#define CMD_DEV_READ_ERROR_STATUS 0xFB
/* endpoint commands */
#define CMD_EP_SELECT 0x00
#define CMD_EP_SELECT_CLEAR 0x40
#define CMD_EP_SET_STATUS 0x40
#define CMD_EP_CLEAR_BUFFER 0xF2
#define CMD_EP_VALIDATE_BUFFER 0xFA
/* set address command */
#define DEV_ADDR (1<<0)
#define DEV_EN (1<<7)
/* configure device command */
#define CONF_DEVICE (1<<0)
/* set mode command */
#define AP_CLK (1<<0)
#define INAK_CI (1<<1)
#define INAK_CO (1<<2)
#define INAK_II (1<<3)
#define INAK_IO (1<<4)
#define INAK_BI (1<<5)
#define INAK_BO (1<<6)
/* set get device status command */
#define CON (1<<0)
#define CON_CH (1<<1)
#define SUS (1<<2)
#define SUS_CH (1<<3)
#define RST (1<<4)
/* get error code command */
// ...
/* Select Endpoint command read bits */
#define EPSTAT_FE (1<<0)
#define EPSTAT_ST (1<<1)
#define EPSTAT_STP (1<<2)
#define EPSTAT_PO (1<<3)
#define EPSTAT_EPN (1<<4)
#define EPSTAT_B1FULL (1<<5)
#define EPSTAT_B2FULL (1<<6)
/* CMD_EP_SET_STATUS command */
#define EP_ST (1<<0)
#define EP_DA (1<<5)
#define EP_RF_MO (1<<6)
#define EP_CND_ST (1<<7)
/* read error status command */
#define PID_ERR (1<<0)
#define UEPKT (1<<1)
#define DCRC (1<<2)
#define TIMEOUT (1<<3)
#define EOP (1<<4)
#define B_OVRN (1<<5)
#define BTSTF (1<<6)
#define TGL_ERR (1<<7)

View File

@ -0,0 +1,117 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
Definitions of structures of standard USB packets
*/
#ifndef _USBSTRUCT_H_
#define _USBSTRUCT_H_
#include "type.h"
/** setup packet definitions */
typedef struct {
u8 bmRequestType; /**< characteristics of the specific request */
u8 bRequest; /**< specific request */
u16 wValue; /**< request specific parameter */
u16 wIndex; /**< request specific parameter */
u16 wLength; /**< length of data transfered in data phase */
} TSetupPacket;
#define REQTYPE_GET_DIR(x) (((x)>>7)&0x01)
#define REQTYPE_GET_TYPE(x) (((x)>>5)&0x03)
#define REQTYPE_GET_RECIP(x) ((x)&0x1F)
#define REQTYPE_DIR_TO_DEVICE 0
#define REQTYPE_DIR_TO_HOST 1
#define REQTYPE_TYPE_STANDARD 0
#define REQTYPE_TYPE_CLASS 1
#define REQTYPE_TYPE_VENDOR 2
#define REQTYPE_TYPE_RESERVED 3
#define REQTYPE_RECIP_DEVICE 0
#define REQTYPE_RECIP_INTERFACE 1
#define REQTYPE_RECIP_ENDPOINT 2
#define REQTYPE_RECIP_OTHER 3
/* standard requests */
#define REQ_GET_STATUS 0x00
#define REQ_CLEAR_FEATURE 0x01
#define REQ_SET_FEATURE 0x03
#define REQ_SET_ADDRESS 0x05
#define REQ_GET_DESCRIPTOR 0x06
#define REQ_SET_DESCRIPTOR 0x07
#define REQ_GET_CONFIGURATION 0x08
#define REQ_SET_CONFIGURATION 0x09
#define REQ_GET_INTERFACE 0x0A
#define REQ_SET_INTERFACE 0x0B
#define REQ_SYNCH_FRAME 0x0C
/* class requests HID */
#define HID_GET_REPORT 0x01
#define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03
#define HID_SET_REPORT 0x09
#define HID_SET_IDLE 0x0A
#define HID_SET_PROTOCOL 0x0B
/* feature selectors */
#define FEA_ENDPOINT_HALT 0x00
#define FEA_REMOTE_WAKEUP 0x01
#define FEA_TEST_MODE 0x02
/*
USB descriptors
*/
/** USB descriptor header */
typedef struct {
u8 bLength; /**< descriptor length */
u8 bDescriptorType; /**< descriptor type */
} TUSBDescHeader;
#define DESC_DEVICE 1
#define DESC_CONFIGURATION 2
#define DESC_STRING 3
#define DESC_INTERFACE 4
#define DESC_ENDPOINT 5
#define DESC_DEVICE_QUALIFIER 6
#define DESC_OTHER_SPEED 7
#define DESC_INTERFACE_POWER 8
#define DESC_HID_HID 0x21
#define DESC_HID_REPORT 0x22
#define DESC_HID_PHYSICAL 0x23
#define GET_DESC_TYPE(x) (((x)>>8)&0xFF)
#define GET_DESC_INDEX(x) ((x)&0xFF)
#endif /* _USBSTRUCT_H_ */

View File

@ -0,0 +1,47 @@
USB stack for LPC17xx. Based on the library distributed by Code Red
Technologies, which in turn is based on the LPCUSB project for the
LPC2148, originally written by Bertrik Sikken.
I'm taking the liberty to just edit the code without annotating
edits, even removing Code Red annotations, as git will preserve
all this history for us.
Original README follows.
Code Red Technologies RDB1768 Board - USB Stack Example
=======================================================
The USB stack and associated examples provided with RDB1768 board are
based on the open source LPCUSB stack, originally written for the NXP
LPC214x microcontrollers. The original sources for the USB stack and
and examples can be found at:
http://sourceforge.net/projects/lpcusb/
with additional information at:
http://wiki.sikken.nl/index.php?title=LPCUSB
We have tried to keep the changes to the codebase down to a minimum, and
have commented where changes have been made as much as possible
Support
-------
This example project is based on the open source LPCUSB stack.
Code Red can provide support on using this project as supplied to
users with a valid support contract with us. But if you require
assistance on the general use of the stack or on extending the
example, then we would recommend that you raise your questions
to an appropriate community forum, such as....
http://tech.groups.yahoo.com/group/lpc2000/messages
USBstack
--------
This is the main project which builds the LPCUSB stack as a library.
This is then used in building the various RDB1768 USB examples projects.

View File

@ -0,0 +1,236 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform_conf.h"
#ifdef BUILD_USB_CDC
/** @file
Control transfer handler.
This module handles control transfers and is normally installed on the
endpoint 0 callback.
Control transfers can be of the following type:
0 Standard;
1 Class;
2 Vendor;
3 Reserved.
A callback can be installed for each of these control transfers using
USBRegisterRequestHandler.
When an OUT request arrives, data is collected in the data store provided
with the USBRegisterRequestHandler call. When the transfer is done, the
callback is called.
When an IN request arrives, the callback is called immediately to either
put the control transfer data in the data store, or to get a pointer to
control transfer data. The data is then packetised and sent to the host.
*/
#include "type.h"
#include "usbdebug.h"
#include "usbstruct.h"
#include "usbapi.h"
#include "utils.h"
#define MAX_CONTROL_SIZE 128 /**< maximum total size of control transfer data */
#define MAX_REQ_HANDLERS 4 /**< standard, class, vendor, reserved */
static TSetupPacket Setup; /**< setup packet */
static u8 *pbData; /**< pointer to data buffer */
static int iResidue; /**< remaining bytes in buffer */
static int iLen; /**< total length of control transfer */
/** Array of installed request handler callbacks */
static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL};
/** Array of installed request data pointers */
static u8 *apbDataStore[4] = {NULL, NULL, NULL, NULL};
/**
Local function to handle a request by calling one of the installed
request handlers.
In case of data going from host to device, the data is at *ppbData.
In case of data going from device to host, the handler can either
choose to write its data at *ppbData or update the data pointer.
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in,out] ppbData Data buffer.
@return TRUE if the request was handles successfully
*/
static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
TFnHandleRequest *pfnHandler;
int iType;
iType = REQTYPE_GET_TYPE(pSetup->bmRequestType);
pfnHandler = apfnReqHandlers[iType];
if (pfnHandler == NULL) {
DBG("No handler for reqtype %d\n", iType);
return FALSE;
}
return pfnHandler(pSetup, piLen, ppbData);
}
/**
Local function to stall the control endpoint
@param [in] bEPStat Endpoint status
*/
static void StallControlPipe(u8 bEPStat)
{
u8 *pb;
int i;
USBHwEPStall(0x80, TRUE);
// dump setup packet
DBG("STALL on [");
pb = (u8 *)&Setup;
for (i = 0; i < 8; i++) {
DBG(" %02x", *pb++);
}
DBG("] stat=%x\n", bEPStat);
}
/**
Sends next chunk of data (possibly 0 bytes) to host
*/
static void DataIn(void)
{
int iChunk;
iChunk = UMIN(MAX_PACKET_SIZE0, iResidue);
USBHwEPWrite(0x80, pbData, iChunk);
pbData += iChunk;
iResidue -= iChunk;
}
/**
* Handles IN/OUT transfers on EP0
*
* @param [in] bEP Endpoint address
* @param [in] bEPStat Endpoint status
*/
void USBHandleControlTransfer(u8 bEP, u8 bEPStat)
{
int iChunk, iType;
if (bEP == 0x00) {
// OUT transfer
if (bEPStat & EP_STATUS_SETUP) {
// setup packet, reset request message state machine
USBHwEPRead(0x00, (u8 *)&Setup, sizeof(Setup));
DBG("S%x", Setup.bRequest);
// defaults for data pointer and residue
iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
pbData = apbDataStore[iType];
iResidue = Setup.wLength;
iLen = Setup.wLength;
if ((Setup.wLength == 0) ||
(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
// ask installed handler to process request
if (!_HandleRequest(&Setup, &iLen, &pbData)) {
DBG("_HandleRequest1 failed\n");
StallControlPipe(bEPStat);
return;
}
// send smallest of requested and offered length
iResidue = UMIN(iLen, Setup.wLength);
// send first part (possibly a zero-length status message)
DataIn();
}
}
else {
if (iResidue > 0) {
// store data
iChunk = USBHwEPRead(0x00, pbData, iResidue);
if (iChunk < 0) {
StallControlPipe(bEPStat);
return;
}
pbData += iChunk;
iResidue -= iChunk;
if (iResidue == 0) {
// received all, send data to handler
iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
pbData = apbDataStore[iType];
if (!_HandleRequest(&Setup, &iLen, &pbData)) {
DBG("_HandleRequest2 failed\n");
StallControlPipe(bEPStat);
return;
}
// send status to host
DataIn();
}
}
else {
// absorb zero-length status message
iChunk = USBHwEPRead(0x00, NULL, 0);
DBG(iChunk > 0 ? "?" : "");
}
}
}
else if (bEP == 0x80) {
// IN transfer
// send more data if available (possibly a 0-length packet)
DataIn();
}
else {
ASSERT(FALSE);
}
}
/**
Registers a callback for handling requests
@param [in] iType Type of request, e.g. REQTYPE_TYPE_STANDARD
@param [in] *pfnHandler Callback function pointer
@param [in] *pbDataStore Data storage area for this type of request
*/
void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, u8 *pbDataStore)
{
ASSERT(iType >= 0);
ASSERT(iType < 4);
apfnReqHandlers[iType] = pfnHandler;
apbDataStore[iType] = pbDataStore;
}
#endif

View File

@ -0,0 +1,532 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform_conf.h"
#ifdef BUILD_USB_CDC
/** @file
USB hardware layer
*/
#include "type.h"
#include "usbdebug.h"
#include "usbhw_lpc.h"
#include "usbapi.h"
/** Installed device interrupt handler */
static TFnDevIntHandler *_pfnDevIntHandler = NULL;
/** Installed endpoint interrupt handlers */
static TFnEPIntHandler *_apfnEPIntHandlers[16];
/** Installed frame interrupt handlers */
static TFnFrameHandler *_pfnFrameHandler = NULL;
/** convert from endpoint address to endpoint index */
#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))
/** convert from endpoint index to endpoint address */
#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))
/**
Local function to wait for a device interrupt (and clear it)
@param [in] dwIntr Bitmask of interrupts to wait for
*/
static void Wait4DevInt(u32 dwIntr)
{
// wait for specific interrupt
while ((LPC_USB->USBDevIntSt & dwIntr) != dwIntr);
// clear the interrupt bits
LPC_USB->USBDevIntClr = dwIntr;
}
/**
Local function to send a command to the USB protocol engine
@param [in] bCmd Command to send
*/
static void USBHwCmd(u8 bCmd)
{
// clear CDFULL/CCEMTY
LPC_USB->USBDevIntClr = CDFULL | CCEMTY;
// write command code
LPC_USB->USBCmdCode = 0x00000500 | (bCmd << 16);
Wait4DevInt(CCEMTY);
}
/**
Local function to send a command + data to the USB protocol engine
@param [in] bCmd Command to send
@param [in] bData Data to send
*/
static void USBHwCmdWrite(u8 bCmd, u16 bData)
{
// write command code
USBHwCmd(bCmd);
// write command data
LPC_USB->USBCmdCode = 0x00000100 | (bData << 16);
Wait4DevInt(CCEMTY);
}
/**
Local function to send a command to the USB protocol engine and read data
@param [in] bCmd Command to send
@return the data
*/
static u8 USBHwCmdRead(u8 bCmd)
{
// write command code
USBHwCmd(bCmd);
// get data
LPC_USB->USBCmdCode = 0x00000200 | (bCmd << 16);
Wait4DevInt(CDFULL);
return LPC_USB->USBCmdData;
}
/**
'Realizes' an endpoint, meaning that buffer space is reserved for
it. An endpoint needs to be realised before it can be used.
From experiments, it appears that a USB reset causes USBReEP to
re-initialise to 3 (= just the control endpoints).
However, a USB bus reset does not disturb the USBMaxPSize settings.
@param [in] idx Endpoint index
@param [in] wMaxPSize Maximum packet size for this endpoint
*/
static void USBHwEPRealize(int idx, u16 wMaxPSize)
{
LPC_USB->USBReEP |= (1 << idx);
LPC_USB->USBEpInd = idx;
LPC_USB->USBMaxPSize = wMaxPSize;
Wait4DevInt(EP_RLZED);
}
/**
Enables or disables an endpoint
@param [in] idx Endpoint index
@param [in] fEnable TRUE to enable, FALSE to disable
*/
static void USBHwEPEnable(int idx, BOOL fEnable)
{
USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
}
/**
Configures an endpoint and enables it
@param [in] bEP Endpoint number
@param [in] wMaxPacketSize Maximum packet size for this EP
*/
void USBHwEPConfig(u8 bEP, u16 wMaxPacketSize)
{
int idx;
idx = EP2IDX(bEP);
// realise EP
USBHwEPRealize(idx, wMaxPacketSize);
// enable EP
USBHwEPEnable(idx, TRUE);
}
/**
Registers an endpoint event callback
@param [in] bEP Endpoint number
@param [in] pfnHandler Callback function
*/
void USBHwRegisterEPIntHandler(u8 bEP, TFnEPIntHandler *pfnHandler)
{
int idx;
idx = EP2IDX(bEP);
ASSERT(idx<32);
/* add handler to list of EP handlers */
_apfnEPIntHandlers[idx / 2] = pfnHandler;
/* enable EP interrupt */
LPC_USB->USBEpIntEn |= (1 << idx);
LPC_USB->USBDevIntEn |= EP_SLOW;
DBG("Registered handler for EP 0x%x\n", bEP);
}
/**
Registers an device status callback
@param [in] pfnHandler Callback function
*/
void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)
{
_pfnDevIntHandler = pfnHandler;
// enable device interrupt
LPC_USB->USBDevIntEn |= DEV_STAT;
DBG("Registered handler for device status\n");
}
/**
Registers the frame callback
@param [in] pfnHandler Callback function
*/
void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)
{
_pfnFrameHandler = pfnHandler;
// enable device interrupt
LPC_USB->USBDevIntEn |= FRAME;
DBG("Registered handler for frame\n");
}
/**
Sets the USB address.
@param [in] bAddr Device address to set
*/
void USBHwSetAddress(u8 bAddr)
{
USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
}
/**
Connects or disconnects from the USB bus
@param [in] fConnect If TRUE, connect, otherwise disconnect
*/
void USBHwConnect(BOOL fConnect)
{
USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);
}
/**
Enables interrupt on NAK condition
For IN endpoints a NAK is generated when the host wants to read data
from the device, but none is available in the endpoint buffer.
For OUT endpoints a NAK is generated when the host wants to write data
to the device, but the endpoint buffer is still full.
The endpoint interrupt handlers can distinguish regular (ACK) interrupts
from NAK interrupt by checking the bits in their bEPStatus argument.
@param [in] bIntBits Bitmap indicating which NAK interrupts to enable
*/
void USBHwNakIntEnable(u8 bIntBits)
{
USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);
}
/**
Gets the status from a specific endpoint.
@param [in] bEP Endpoint number
@return Endpoint status byte (containing EP_STATUS_xxx bits)
*/
u8 USBHwEPGetStatus(u8 bEP)
{
int idx = EP2IDX(bEP);
return USBHwCmdRead(CMD_EP_SELECT | idx);
}
/**
Sets the stalled property of an endpoint
@param [in] bEP Endpoint number
@param [in] fStall TRUE to stall, FALSE to unstall
*/
void USBHwEPStall(u8 bEP, BOOL fStall)
{
int idx = EP2IDX(bEP);
USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
}
/**
Writes data to an endpoint buffer
@param [in] bEP Endpoint number
@param [in] pbBuf Endpoint data
@param [in] iLen Number of bytes to write
@return TRUE if the data was successfully written or <0 in case of error.
*/
int USBHwEPWrite(u8 bEP, u8 *pbBuf, int iLen)
{
int idx;
idx = EP2IDX(bEP);
// set write enable for specific endpoint
LPC_USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2);
// set packet length
LPC_USB->USBTxPLen = iLen;
// write data
while (LPC_USB->USBCtrl & WR_EN) {
LPC_USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];
pbBuf += 4;
}
// select endpoint and validate buffer
USBHwCmd(CMD_EP_SELECT | idx);
USBHwCmd(CMD_EP_VALIDATE_BUFFER);
return iLen;
}
/**
Reads data from an endpoint buffer
@param [in] bEP Endpoint number
@param [in] pbBuf Endpoint data
@param [in] iMaxLen Maximum number of bytes to read
@return the number of bytes available in the EP (possibly more than iMaxLen),
or <0 in case of error.
*/
int USBHwEPRead(u8 bEP, u8 *pbBuf, int iMaxLen)
{
int i, idx;
u32 dwData, dwLen;
idx = EP2IDX(bEP);
// set read enable bit for specific endpoint
LPC_USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2);
// wait for PKT_RDY
do {
dwLen = LPC_USB->USBRxPLen;
} while ((dwLen & PKT_RDY) == 0);
// packet valid?
if ((dwLen & DV) == 0) {
return -1;
}
// get length
dwLen &= PKT_LNGTH_MASK;
// get data
dwData = 0;
for (i = 0; i < dwLen; i++) {
if ((i % 4) == 0) {
dwData = LPC_USB->USBRxData;
}
if ((pbBuf != NULL) && (i < iMaxLen)) {
pbBuf[i] = dwData & 0xFF;
}
dwData >>= 8;
}
// make sure RD_EN is clear
LPC_USB->USBCtrl = 0;
// select endpoint and clear buffer
USBHwCmd(CMD_EP_SELECT | idx);
USBHwCmd(CMD_EP_CLEAR_BUFFER);
return dwLen;
}
/**
Sets the 'configured' state.
All registered endpoints are 'realised' and enabled, and the
'configured' bit is set in the device status register.
@param [in] fConfigured If TRUE, configure device, else unconfigure
*/
void USBHwConfigDevice(BOOL fConfigured)
{
// set configured bit
USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
}
/**
USB interrupt handler
@todo Get all 11 bits of frame number instead of just 8
Endpoint interrupts are mapped to the slow interrupt
*/
void USBHwISR(void)
{
u32 dwStatus;
u32 dwIntBit;
u8 bEPStat, bDevStat, bStat;
int i;
u16 wFrame;
// handle device interrupts
dwStatus = LPC_USB->USBDevIntSt;
// frame interrupt
if (dwStatus & FRAME) {
// clear int
LPC_USB->USBDevIntClr = FRAME;
// call handler
if (_pfnFrameHandler != NULL) {
wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR);
_pfnFrameHandler(wFrame);
}
}
// device status interrupt
if (dwStatus & DEV_STAT) {
/* Clear DEV_STAT interrupt before reading DEV_STAT register.
This prevents corrupted device status reads, see
LPC2148 User manual revision 2, 25 july 2006.
*/
LPC_USB->USBDevIntClr = DEV_STAT;
bDevStat = USBHwCmdRead(CMD_DEV_STATUS);
if (bDevStat & (CON_CH | SUS_CH | RST)) {
// convert device status into something HW independent
bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
((bDevStat & RST) ? DEV_STATUS_RESET : 0);
// call handler
if (_pfnDevIntHandler != NULL) {
_pfnDevIntHandler(bStat);
}
}
}
// endpoint interrupt
if (dwStatus & EP_SLOW) {
// clear EP_SLOW
LPC_USB->USBDevIntClr = EP_SLOW;
// check all endpoints
for (i = 0; i < 32; i++) {
dwIntBit = (1 << i);
if (LPC_USB->USBEpIntSt & dwIntBit) {
// clear int (and retrieve status)
LPC_USB->USBEpIntClr = dwIntBit;
Wait4DevInt(CDFULL);
bEPStat = LPC_USB->USBCmdData;
// convert EP pipe stat into something HW independent
bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
// call handler
if (_apfnEPIntHandlers[i / 2] != NULL) {
_apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);
}
}
}
}
}
/**
Initialises the USB hardware
To make sure this works, I/O pin functions need to be mapped inside
the board description as follows:
* P0.29 USB D+
* P0.30 USB D-
* P1.18 USB_UP_LED
* P2.9 USB CONNECT
To do this, use a map_pins clause inside the configuration section
as follows:
map_pins = {
port = { 0, 0, 1, 2 },
pin = { 29, 30, 18, 9 },
pinfunction = { 1, 1, 1, 1 }
}
@return TRUE if the hardware was successfully initialised
*/
BOOL USBHwInit(void)
{
// enable PUSB
LPC_SC->PCONP |= (1 << 31);
LPC_USB->USBClkCtrl = 0x1A; /* Dev clock, AHB clock enable */
while ((LPC_USB->USBClkSt & 0x1A) != 0x1A);
// disable/clear all interrupts for now
LPC_USB->USBDevIntEn = 0;
LPC_USB->USBDevIntClr = 0xFFFFFFFF;
LPC_USB->USBDevIntPri = 0;
LPC_USB->USBEpIntEn = 0;
LPC_USB->USBEpIntClr = 0xFFFFFFFF;
LPC_USB->USBEpIntPri = 0;
// by default, only ACKs generate interrupts
USBHwNakIntEnable(0);
return TRUE;
}
#endif

View File

@ -0,0 +1,87 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform_conf.h"
#ifdef BUILD_USB_CDC
/** @file
USB stack initialisation
*/
#include "type.h"
#include "usbdebug.h"
#include "usbapi.h"
/** data storage area for standard requests */
static u8 abStdReqData[8];
/**
USB reset handler
@param [in] bDevStatus Device status
*/
static void HandleUsbReset(u8 bDevStatus)
{
if (bDevStatus & DEV_STATUS_RESET) {
DBG("\n!");
}
}
/**
Initialises the USB hardware and sets up the USB stack by
installing default callbacks.
@return TRUE if initialisation was successful
*/
BOOL USBInit(void)
{
// init hardware
USBHwInit();
// register bus reset handler
USBHwRegisterDevIntHandler(HandleUsbReset);
// register control transfer handler on EP0
USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer);
USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer);
// setup control endpoints
USBHwEPConfig(0x00, MAX_PACKET_SIZE0);
USBHwEPConfig(0x80, MAX_PACKET_SIZE0);
// register standard request handler
USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData);
return TRUE;
}
#endif

View File

@ -0,0 +1,436 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform_conf.h"
#ifdef BUILD_USB_CDC
/** @file
Standard request handler.
This modules handles the 'chapter 9' processing, specifically the
standard device requests in table 9-3 from the universal serial bus
specification revision 2.0
Specific types of devices may specify additional requests (for example
HID devices add a GET_DESCRIPTOR request for interfaces), but they
will not be part of this module.
@todo some requests have to return a request error if device not configured:
@todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
@todo this applies to the following if endpoint != 0:
@todo SET_FEATURE, GET_FEATURE
*/
#include "type.h"
#include "usbdebug.h"
#include "usbstruct.h"
#include "usbapi.h"
#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */
/* general descriptor field offsets */
#define DESC_bLength 0 /**< length offset */
#define DESC_bDescriptorType 1 /**< descriptor type offset */
/* config descriptor field offsets */
#define CONF_DESC_wTotalLength 2 /**< total length offset */
#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */
#define CONF_DESC_bmAttributes 7 /**< configuration characteristics */
/* interface descriptor field offsets */
#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */
/* endpoint descriptor field offsets */
#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */
#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */
/** Currently selected configuration */
static u8 bConfiguration = 0;
/** Installed custom request handler */
static TFnHandleRequest *pfnHandleCustomReq = NULL;
/** Pointer to registered descriptors */
static const u8 *pabDescrip = NULL;
/**
Registers a pointer to a descriptor block containing all descriptors
for the device.
@param [in] pabDescriptors The descriptor byte array
*/
void USBRegisterDescriptors(const u8 *pabDescriptors)
{
pabDescrip = pabDescriptors;
}
/**
Parses the list of installed USB descriptors and attempts to find
the specified USB descriptor.
@param [in] wTypeIndex Type and index of the descriptor
@param [in] wLangID Language ID of the descriptor (currently unused)
@param [out] *piLen Descriptor length
@param [out] *ppbData Descriptor data
@return TRUE if the descriptor was found, FALSE otherwise
*/
BOOL USBGetDescriptor(u16 wTypeIndex, u16 wLangID, int *piLen, u8 **ppbData)
{
u8 bType, bIndex;
u8 *pab;
int iCurIndex;
ASSERT(pabDescrip != NULL);
bType = GET_DESC_TYPE(wTypeIndex);
bIndex = GET_DESC_INDEX(wTypeIndex);
pab = (u8 *)pabDescrip;
iCurIndex = 0;
while (pab[DESC_bLength] != 0) {
if (pab[DESC_bDescriptorType] == bType) {
if (iCurIndex == bIndex) {
// set data pointer
*ppbData = pab;
// get length from structure
if (bType == DESC_CONFIGURATION) {
// configuration descriptor is an exception, length is at offset 2 and 3
*piLen = (pab[CONF_DESC_wTotalLength]) |
(pab[CONF_DESC_wTotalLength + 1] << 8);
}
else {
// normally length is at offset 0
*piLen = pab[DESC_bLength];
}
return TRUE;
}
iCurIndex++;
}
// skip to next descriptor
pab += pab[DESC_bLength];
}
// nothing found
DBG("Desc %x not found!\n", wTypeIndex);
return FALSE;
}
/**
Configures the device according to the specified configuration index and
alternate setting by parsing the installed USB descriptor list.
A configuration index of 0 unconfigures the device.
@param [in] bConfigIndex Configuration index
@param [in] bAltSetting Alternate setting number
@todo function always returns TRUE, add stricter checking?
@return TRUE if successfully configured, FALSE otherwise
*/
static BOOL USBSetConfiguration(u8 bConfigIndex, u8 bAltSetting)
{
u8 *pab;
u8 bCurConfig, bCurAltSetting;
u8 bEP;
u16 wMaxPktSize;
ASSERT(pabDescrip != NULL);
if (bConfigIndex == 0) {
// unconfigure device
USBHwConfigDevice(FALSE);
}
else {
// configure endpoints for this configuration/altsetting
pab = (u8 *)pabDescrip;
bCurConfig = 0xFF;
bCurAltSetting = 0xFF;
while (pab[DESC_bLength] != 0) {
switch (pab[DESC_bDescriptorType]) {
case DESC_CONFIGURATION:
// remember current configuration index
bCurConfig = pab[CONF_DESC_bConfigurationValue];
break;
case DESC_INTERFACE:
// remember current alternate setting
bCurAltSetting = pab[INTF_DESC_bAlternateSetting];
break;
case DESC_ENDPOINT:
if ((bCurConfig == bConfigIndex) &&
(bCurAltSetting == bAltSetting)) {
// endpoint found for desired config and alternate setting
bEP = pab[ENDP_DESC_bEndpointAddress];
wMaxPktSize = (pab[ENDP_DESC_wMaxPacketSize]) |
(pab[ENDP_DESC_wMaxPacketSize + 1] << 8);
// configure endpoint
USBHwEPConfig(bEP, wMaxPktSize);
}
break;
default:
break;
}
// skip to next descriptor
pab += pab[DESC_bLength];
}
// configure device
USBHwConfigDevice(TRUE);
}
return TRUE;
}
/**
Local function to handle a standard device request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in,out] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
u8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// bit 0: self-powered
// bit 1: remote wakeup = not supported
pbData[0] = 0;
pbData[1] = 0;
*piLen = 2;
break;
case REQ_SET_ADDRESS:
USBHwSetAddress(pSetup->wValue);
break;
case REQ_GET_DESCRIPTOR:
DBG("D%x", pSetup->wValue);
return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);
case REQ_GET_CONFIGURATION:
// indicate if we are configured
pbData[0] = bConfiguration;
*piLen = 1;
break;
case REQ_SET_CONFIGURATION:
if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {
DBG("USBSetConfiguration failed!\n");
return FALSE;
}
// configuration successful, update current configuration
bConfiguration = pSetup->wValue & 0xFF;
break;
case REQ_CLEAR_FEATURE:
case REQ_SET_FEATURE:
if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
// put DEVICE_REMOTE_WAKEUP code here
}
if (pSetup->wValue == FEA_TEST_MODE) {
// put TEST_MODE code here
}
return FALSE;
case REQ_SET_DESCRIPTOR:
DBG("Device req %d not implemented\n", pSetup->bRequest);
return FALSE;
default:
DBG("Illegal device req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Local function to handle a standard interface request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdInterfaceReq(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
u8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// no bits specified
pbData[0] = 0;
pbData[1] = 0;
*piLen = 2;
break;
case REQ_CLEAR_FEATURE:
case REQ_SET_FEATURE:
// not defined for interface
return FALSE;
case REQ_GET_INTERFACE: // TODO use bNumInterfaces
// there is only one interface, return n-1 (= 0)
pbData[0] = 0;
*piLen = 1;
break;
case REQ_SET_INTERFACE: // TODO use bNumInterfaces
// there is only one interface (= 0)
if (pSetup->wValue != 0) {
return FALSE;
}
*piLen = 0;
break;
default:
DBG("Illegal interface req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Local function to handle a standard endpoint request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
u8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// bit 0 = endpointed halted or not
pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0;
pbData[1] = 0;
*piLen = 2;
break;
case REQ_CLEAR_FEATURE:
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
// clear HALT by unstalling
USBHwEPStall(pSetup->wIndex, FALSE);
break;
}
// only ENDPOINT_HALT defined for endpoints
return FALSE;
case REQ_SET_FEATURE:
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
// set HALT by stalling
USBHwEPStall(pSetup->wIndex, TRUE);
break;
}
// only ENDPOINT_HALT defined for endpoints
return FALSE;
case REQ_SYNCH_FRAME:
DBG("EP req %d not implemented\n", pSetup->bRequest);
return FALSE;
default:
DBG("Illegal EP req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Default handler for standard ('chapter 9') requests
If a custom request handler was installed, this handler is called first.
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
// try the custom request handler first
if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {
return TRUE;
}
switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {
case REQTYPE_RECIP_DEVICE: return HandleStdDeviceReq(pSetup, piLen, ppbData);
case REQTYPE_RECIP_INTERFACE: return HandleStdInterfaceReq(pSetup, piLen, ppbData);
case REQTYPE_RECIP_ENDPOINT: return HandleStdEndPointReq(pSetup, piLen, ppbData);
default: return FALSE;
}
}
/**
Registers a callback for custom device requests
In USBHandleStandardRequest, the custom request handler gets a first
chance at handling the request before it is handed over to the 'chapter 9'
request handler.
This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
request is sent to an interface, which is not covered by the 'chapter 9'
specification.
@param [in] pfnHandler Callback function pointer
*/
void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)
{
pfnHandleCustomReq = pfnHandler;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
-- Configuration file for the LPC23xx backend
local cpumode = ( builder:get_option( 'cpumode' ) or 'arm' ):lower()
specific_files = "startup.s irq.c target.c platform.c platform_int.c"
local ldscript = "lpc2368.lds"
-- Prepend with path
specific_files = utils.prepend_path( specific_files, sf( "src/platform/%s", platform ) )
specific_files = specific_files .. " src/platform/arm_utils.s src/platform/arm_cortex_interrupts.c"
ldscript = sf( "src/platform/%s/%s", platform, ldscript )
addm{ "FOR" .. comp.cpu:upper(), 'gcc' }
-- Standard GCC Flags
addcf{ '-ffunction-sections', '-fdata-sections', '-fno-strict-aliasing', '-Wall' }
addlf{ '-nostartfiles', '-nostdlib', '-T', ldscript, '-Wl,--gc-sections', '-Wl,--allow-multiple-definition' }
addaf{ '-x', 'assembler-with-cpp', '-Wall' }
addlib{ 'c','gcc','m' }
-- Specific target configuration
local target_flags = '-mcpu=arm7tdmi'
if cpumode == 'thumb' then
target_flags = { target_flags, '-mthumb' }
addm( 'CPUMODE_THUMB' )
else
addm( 'CPUMODE_ARM' )
end
addcf( target_flags )
addlf{ target_flags, '-Wl,-e,entry' }
addaf{ target_flags, '-D___ASSEMBLY__' }
-- Toolset data
tools.lpc23xx = {}
-- Array of file names that will be checked against the 'prog' target; their absence will force a rebuild
tools.lpc23xx.prog_flist = { output .. ".hex" }
-- We use 'gcc' as the assembler
toolset.asm = toolset.compile

View File

@ -0,0 +1,48 @@
// LPC2368 CPU definitions
#ifndef __CPU_LPC2368_H__
#define __CPU_LPC2368_H__
#include "stacks.h"
#include "target.h"
#include "platform_ints.h"
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 16
#define NUM_SPI 1
#define NUM_UART 3
#define NUM_TIMER 4
#define NUM_PHYS_TIMER 0
#define NUM_PWM 6
#define NUM_ADC 6
#define NUM_CAN 2
// ADC Configuration Params
#define ADC_BIT_RESOLUTION 10
// CPU frequency (needed by the CPU module and MMCFS code, 0 if not used)
#define CPU_FREQUENCY Fcclk
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX '0'
// Pins per port configuration:
// #define PIO_PINS_PER_PORT (n) if each port has the same number of pins, or
// #define PIO_PIN_ARRAY { n1, n2, ... } to define pins per port in an array
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 32
// Internal RAM
#define SRAM_ORIGIN 0x40000000
#define SRAM_SIZE ( 32 * 1024 ) // [TODO]: make this 96k?
#define INTERNAL_RAM1_FIRST_FREE end
#define INTERNAL_RAM1_LAST_FREE ( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 )
// Interrupt list for this CPU
#define PLATFORM_CPU_CONSTANTS_INTS\
_C( INT_GPIO_POSEDGE ), \
_C( INT_GPIO_NEGEDGE ), \
_C( INT_TMR_MATCH ), \
_C( INT_UART_RX ),
#endif // #ifndef __CPU_LPC2368_H__

108
src/platform/lpc23xx/irq.c Normal file
View File

@ -0,0 +1,108 @@
/*****************************************************************************
* irq.c: Interrupt handler C file for NXP LPC23xx/24xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.07.13 ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
#include "LPC23xx.h" /* LPC23XX/24xx Peripheral Registers */
#include "type.h"
#include "irq.h"
#if FIQ
#include "timer.h"
#endif
/******************************************************************************
** Function name: FIQ_Handler
**
** Descriptions: FIQ interrupt handler called in startup
** parameters:
**
** Returned value:
**
******************************************************************************/
// [TODO] make this GCC compatible if needed
#if FIQ
void FIQ_Handler( void ) __irq
{
//#if FIQ
if ( VICFIQStatus & (0x1<<4) && VICIntEnable & (0x1<<4) )
{
Timer0FIQHandler();
}
if ( VICFIQStatus & (0x1<<5) && VICIntEnable & (0x1<<5) )
{
Timer1FIQHandler();
}
return;
//#endif
}
#endif
/* Initialize the interrupt controller */
/******************************************************************************
** Function name: init_VIC
**
** Descriptions: Initialize VIC interrupt controller.
** parameters: None
** Returned value: None
**
******************************************************************************/
void init_VIC(void)
{
DWORD i = 0;
DWORD *vect_addr, *vect_prio;
/* initialize VIC*/
VICIntEnClr = 0xffffffff;
VICVectAddr = 0;
VICIntSelect = 0;
/* set all the vector and vector control register to 0 */
for ( i = 0; i < VIC_SIZE; i++ )
{
vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + i*4);
vect_prio = (DWORD *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + i*4);
*vect_addr = 0x0;
*vect_prio = 0xF;
}
return;
}
/******************************************************************************
** Function name: install_irq
**
** Descriptions: Install interrupt handler
** parameters: Interrupt number, interrupt handler address,
** interrupt priority
** Returned value: true or false, return false if IntNum is out of range
**
******************************************************************************/
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )
{
DWORD *vect_addr;
DWORD *vect_prio;
VICIntEnClr = 1 << IntNumber; /* Disable Interrupt */
if ( IntNumber >= VIC_SIZE )
{
return ( FALSE );
}
else
{
/* find first un-assigned VIC address for the handler */
vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);
vect_prio = (DWORD *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + IntNumber*4);
*vect_addr = (DWORD)HandlerAddr; /* set interrupt vector */
*vect_prio = Priority;
VICIntEnable |= 1 << IntNumber; /* Enable Interrupt */
return( TRUE );
}
}
/******************************************************************************
** End Of File
******************************************************************************/

View File

@ -0,0 +1,79 @@
/******************************************************************************
* irq.h: Interrupt related Header file for NXP LPC23xx/24xx Family
* Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.09.01 ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
#ifndef __IRQ_H
#define __IRQ_H
#define I_Bit 0x80
#define F_Bit 0x40
#define SYS32Mode 0x1F
#define IRQ32Mode 0x12
#define FIQ32Mode 0x11
/* Use FIQ, set below to 1, otherwise, it's 0 */
#define FIQ 0
#define HIGHEST_PRIORITY 0x01
#define LOWEST_PRIORITY 0x0F
#define WDT_INT 0
#define SWI_INT 1
#define ARM_CORE0_INT 2
#define ARM_CORE1_INT 3
#define TIMER0_INT 4
#define TIMER1_INT 5
#define UART0_INT 6
#define UART1_INT 7
#define PWM0_1_INT 8
#define I2C0_INT 9
#define SPI0_INT 10 /* SPI and SSP0 share VIC slot */
#define SSP0_INT 10
#define SSP1_INT 11
#define PLL_INT 12
#define RTC_INT 13
#define EINT0_INT 14
#define EINT1_INT 15
#define EINT2_INT 16
#define EINT3_INT 17
#define ADC0_INT 18
#define I2C1_INT 19
#define BOD_INT 20
#define EMAC_INT 21
#define USB_INT 22
#define CAN_INT 23
#define MCI_INT 24
#define GPDMA_INT 25
#define TIMER2_INT 26
#define TIMER3_INT 27
#define UART2_INT 28
#define UART3_INT 29
#define I2C2_INT 30
#define I2S_INT 31
#define VIC_SIZE 32
#define VECT_ADDR_INDEX 0x100
#define VECT_PRIO_INDEX 0x200
/* Be aware that, from compiler to compiler, nested interrupt will have to
be handled differently. More details can be found in Philips LPC2000
family app-note AN10381 */
void init_VIC( void );
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority );
#endif /* end __IRQ_H */
/******************************************************************************
** End Of File
******************************************************************************/

View File

@ -0,0 +1,63 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY
{
sram (W!RX) : ORIGIN = 0x40000000, LENGTH = 32k
flash (RX) : ORIGIN = 0x0, LENGTH = 512k
}
SECTIONS
{
.fixed :
{
. = ALIGN(4);
_sfixed = .;
PROVIDE(stext = .);
KEEP(*(.vectors))
*(.text .text.*)
*(.rodata .rodata.*)
*(.gnu.linkonce.t.*)
*(.glue_7)
*(.glue_7t)
*(.gcc_except_table)
*(.gnu.linkonce.r.*)
. = ALIGN(4);
_efixed = .;
PROVIDE(etext = .);
_fini = .;
*(.fini)
} >flash
.relocate : AT (_efixed)
{
. = ALIGN(4);
_srelocate = .;
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(4);
_erelocate = .;
} >sram
.ARM.extab :
{
*(.ARM.extab*)
} >sram
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx*)
} >sram
__exidx_end = .;
.bss (NOLOAD) : {
_szero = .;
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
_ezero = .;
} >sram
end = .;
}

View File

@ -0,0 +1,834 @@
// Platform-dependent functions
#include "platform.h"
#include "type.h"
#include "devman.h"
#include "genstd.h"
#include "stacks.h"
#include <reent.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "utils.h"
#include "common.h"
#include "elua_adc.h"
#include "platform_conf.h"
#include "buf.h"
#include "elua_int.h"
#include "arm_constants.h"
// Platform includes
#include "LPC23xx.h" /* LPC23xx/24xx definitions */
#include "target.h"
#include "irq.h"
#include "uart.h"
extern void enable_ints();
extern void disable_ints();
// ****************************************************************************
// Platform initialization
static void platform_setup_timers();
static void platform_setup_pwm();
static void platform_setup_adcs();
// Power management definitions
enum
{
PCUART2 = 1ULL << 24,
PCUART3 = 1ULL << 25,
PCTIM2 = 1ULL << 22,
PCTIM3 = 1ULL << 23,
PCADC = 1ULL << 12
};
// CPU initialization
static void platform_setup_cpu()
{
// Enable clock for UART2 and UART3
PCONP |= PCUART2 | PCUART3;
// Set clock for all the UARTs to the system clock (helps in baud generation)
PCLKSEL0 = ( PCLKSEL0 & 0xFFFFFC3F ) | 0x00000140;
PCLKSEL1 = ( PCLKSEL1 & 0xFFF0FFFF ) | 0x00050000;
// Enable clock for Timer 2 and Timer 3
PCONP |= PCTIM2 | PCTIM3;
// Setup GPIO0 and GPIO1 in fast mode
SCS |= 1;
}
int platform_init()
{
// Complete CPU initialization
platform_setup_cpu();
// External memory
//platform_setup_extmem();
// Setup peripherals
platform_setup_timers();
platform_setup_pwm();
#ifdef BUILD_ADC
// Setup ADCs
platform_setup_adcs();
#endif
// Common platform initialization code
cmn_platform_init();
return PLATFORM_OK;
}
// ****************************************************************************
// PIO section
static const u32 pio_fiodir[ NUM_PIO ] = { ( u32 )&FIO0DIR, ( u32 )&FIO1DIR, ( u32 )&FIO2DIR, ( u32 )&FIO3DIR, ( u32 )&FIO4DIR };
static const u32 pio_fiopin[ NUM_PIO ] = { ( u32 )&FIO0PIN, ( u32 )&FIO1PIN, ( u32 )&FIO2PIN, ( u32 )&FIO3PIN, ( u32 )&FIO4PIN };
static const u32 pio_fioset[ NUM_PIO ] = { ( u32 )&FIO0SET, ( u32 )&FIO1SET, ( u32 )&FIO2SET, ( u32 )&FIO3SET, ( u32 )&FIO4SET };
static const u32 pio_fioclr[ NUM_PIO ] = { ( u32 )&FIO0CLR, ( u32 )&FIO1CLR, ( u32 )&FIO2CLR, ( u32 )&FIO3CLR, ( u32 )&FIO4CLR };
static const u32 pio_pinmode[ NUM_PIO * 2 ] = { ( u32 )&PINMODE0, ( u32 )&PINMODE1, ( u32 )&PINMODE2, ( u32 )&PINMODE3, ( u32 )&PINMODE4,
( u32 )&PINMODE5, ( u32 )&PINMODE6, ( u32 )&PINMODE7, ( u32 )&PINMODE8, ( u32 )&PINMODE9 };
// The platform I/O functions
pio_type platform_pio_op( unsigned port, pio_type pinmask, int op )
{
pio_type retval = 1;
PREG FIOxDIR = ( PREG )pio_fiodir[ port ];
PREG FIOxPIN = ( PREG )pio_fiopin[ port ];
PREG FIOxSET = ( PREG )pio_fioset[ port ];
PREG FIOxCLR = ( PREG )pio_fioclr[ port ];
PREG PINxMODE0 = ( PREG )pio_pinmode[ port * 2 ];
PREG PINxMODE1 = ( PREG )pio_pinmode[ port * 2 + 1 ];
u32 mask;
switch( op )
{
case PLATFORM_IO_PORT_SET_VALUE:
*FIOxPIN = pinmask;
break;
case PLATFORM_IO_PIN_SET:
*FIOxSET = pinmask;
break;
case PLATFORM_IO_PIN_CLEAR:
*FIOxCLR = pinmask;
break;
case PLATFORM_IO_PORT_DIR_OUTPUT:
*FIOxDIR = 0xFFFFFFFF;
break;
case PLATFORM_IO_PIN_DIR_OUTPUT:
*FIOxDIR |= pinmask;
break;
case PLATFORM_IO_PORT_DIR_INPUT:
*FIOxDIR = 0;
break;
case PLATFORM_IO_PIN_DIR_INPUT:
*FIOxDIR &= ~pinmask;
break;
case PLATFORM_IO_PORT_GET_VALUE:
retval = *FIOxPIN;
break;
case PLATFORM_IO_PIN_GET:
retval =( *FIOxPIN & pinmask ) ? 1 : 0;
break;
case PLATFORM_IO_PIN_PULLUP:
if( port == 0 && ( pinmask & 0xF8000000 ) )
printf( "Unable to set pullups on specified pin(s).\n" );
else
{
for( mask = 1; mask < 16; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE0 = *PINxMODE0 & ~( 3 << ( mask * 2 ) );
for( mask = 16; mask < 32; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE1 = *PINxMODE1 & ~( 3 << ( mask * 2 ) );
}
break;
case PLATFORM_IO_PIN_PULLDOWN:
if( port == 0 && ( pinmask & 0xF8000000 ) )
printf( "Unable to set pulldowns on specified pin(s).\n" );
else
{
for( mask = 1; mask < 16; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE0 = ( *PINxMODE0 & ~( 3 << ( mask * 2 ) ) ) | ( 3 << ( mask * 2 ) );
for( mask = 16; mask < 32; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE1 = ( *PINxMODE1 & ~( 3 << ( mask * 2 ) ) ) | ( 3 << ( mask * 2 ) );
}
break;
case PLATFORM_IO_PIN_NOPULL:
if( port == 0 && ( pinmask & 0xF8000000 ) )
printf( "Unable to reset pullups/pulldowns on specified pin(s).\n" );
else
{
for( mask = 1; mask < 16; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE0 = ( *PINxMODE0 & ~( 3 << ( mask * 2 ) ) ) | ( 2 << ( mask * 2 ) );
for( mask = 16; mask < 32; mask ++ )
if( pinmask & ( 1 << mask ) )
*PINxMODE1 = ( *PINxMODE1 & ~( 3 << ( mask * 2 ) ) ) | ( 2 << ( mask * 2 ) );
}
break;
default:
retval = 0;
break;
}
return retval;
}
// ****************************************************************************
// UART section
// UART0: Rx = P0.3, Tx = P0.2
// The other UARTs have assignable Rx/Tx pins and thus have to be configured
// by the user
static const u32 uart_lcr[ NUM_UART ] = { ( u32 )&U0LCR, ( u32 )&U1LCR, ( u32 )&U2LCR, ( u32 )&U3LCR };
static const u32 uart_dlm[ NUM_UART ] = { ( u32 )&U0DLM, ( u32 )&U1DLM, ( u32 )&U2DLM, ( u32 )&U3DLM };
static const u32 uart_dll[ NUM_UART ] = { ( u32 )&U0DLL, ( u32 )&U1DLL, ( u32 )&U2DLL, ( u32 )&U3DLL };
static const u32 uart_fcr[ NUM_UART ] = { ( u32 )&U0FCR, ( u32 )&U1FCR, ( u32 )&U2FCR, ( u32 )&U3FCR };
static const u32 uart_thr[ NUM_UART ] = { ( u32 )&U0THR, ( u32 )&U1THR, ( u32 )&U2THR, ( u32 )&U3THR };
static const u32 uart_lsr[ NUM_UART ] = { ( u32 )&U0LSR, ( u32 )&U1LSR, ( u32 )&U2LSR, ( u32 )&U3LSR };
static const u32 uart_rbr[ NUM_UART ] = { ( u32 )&U0RBR, ( u32 )&U1RBR, ( u32 )&U2RBR, ( u32 )&U3RBR };
static const u32 uart_fdr[ NUM_UART ] = { ( u32 )&U0FDR, ( u32 )&U1FDR, ( u32 )&U2FDR, ( u32 )&U3FDR };
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int stopbits )
{
u32 temp, uclk, mul_frac_div, div_add_frac_div;
u32 diviser = 0;
u32 mul_frac_div_opt = 0;
u32 div_add_opt = 0;
u32 div_opt = 0;
u32 calc_baud = 0;
u32 rel_err = 0;
u32 rel_err_opt = 100000;
PREG UxLCR = ( PREG )uart_lcr[ id ];
PREG UxDLM = ( PREG )uart_dlm[ id ];
PREG UxDLL = ( PREG )uart_dll[ id ];
PREG UxFCR = ( PREG )uart_fcr[ id ];
PREG UxFDR = ( PREG )uart_fdr[ id ];
// Set data bits, parity, stop bit
temp = 0;
switch( databits )
{
case 5:
temp |= UART_DATABITS_5;
break;
case 6:
temp |= UART_DATABITS_6;
break;
case 7:
temp |= UART_DATABITS_7;
break;
case 8:
temp |= UART_DATABITS_8;
break;
}
if( stopbits == PLATFORM_UART_STOPBITS_2 )
temp |= UART_STOPBITS_2;
else
temp |= UART_STOPBITS_1;
if( parity != PLATFORM_UART_PARITY_NONE )
{
temp |= UART_PARITY_ENABLE;
if( parity == PLATFORM_UART_PARITY_ODD )
temp |= UART_PARITY_ODD;
else
temp |= UART_PARITY_EVEN;
}
*UxLCR = temp;
// Divisor computation
//temp = ( Fpclk_UART >> 4 ) / baud;
uclk = Fpclk_UART >> 4;
for( mul_frac_div = 1; mul_frac_div <= 15; mul_frac_div++ )
{
for( div_add_frac_div = 1; div_add_frac_div <= 15; div_add_frac_div++ )
{
temp = ( mul_frac_div * uclk ) / ( ( mul_frac_div + div_add_frac_div ) );
diviser = temp / baud;
if ( ( temp % baud ) > ( baud / 2 ) )
diviser++;
if ( diviser > 2 && diviser < 65536 )
{
calc_baud = temp / diviser;
if (calc_baud <= baud)
rel_err = baud - calc_baud;
if ((rel_err < rel_err_opt))
{
mul_frac_div_opt = mul_frac_div ;
div_add_opt = div_add_frac_div;
div_opt = diviser;
rel_err_opt = rel_err;
if (rel_err == 0)
break;
}
}
}
}
// Set baud and divisors
*UxLCR |= UART_DLAB_ENABLE;
*UxDLM = div_opt >> 8;
*UxDLL = div_opt & 0xFF;
*UxLCR &= ~UART_DLAB_ENABLE;
*UxFDR = ( ( mul_frac_div_opt << 4 ) & 0xF0 ) | ( div_add_opt & 0x0F );
// Enable and reset Tx and Rx FIFOs
*UxFCR = UART_FIFO_ENABLE | UART_RXFIFO_RESET | UART_TXFIFO_RESET;
// Setup PIOs for UART0. For the other ports, the user needs to specify what pin(s)
// are allocated for UART Rx/Tx.
if( id == 0 )
PINSEL0 = ( PINSEL0 & 0xFFFFFF0F ) | 0x00000050;
// Return the actual baud
return ( Fpclk_UART >> 4 ) / temp;
}
void platform_s_uart_send( unsigned id, u8 data )
{
PREG UxTHR = ( PREG )uart_thr[ id ];
PREG UxLSR = ( PREG )uart_lsr[ id ];
while( ( *UxLSR & LSR_THRE ) == 0 );
*UxTHR = data;
}
int platform_s_uart_recv( unsigned id, timer_data_type timeout )
{
PREG UxLSR = ( PREG )uart_lsr[ id ];
PREG UxRBR = ( PREG )uart_rbr[ id ];
if( timeout == 0 )
{
// Return data only if already available
if( *UxLSR & LSR_RDR )
return *UxRBR;
else
return -1;
}
else
while( ( *UxLSR & LSR_RDR ) == 0 );
return *UxRBR;
}
int platform_s_uart_set_flow_control( unsigned id, int type )
{
return PLATFORM_ERR;
}
// ****************************************************************************
// Timer section
static const u32 tmr_tcr[] = { ( u32 )&T0TCR, ( u32 )&T1TCR, ( u32 )&T2TCR, ( u32 )&T3TCR };
static const u32 tmr_tc[] = { ( u32 )&T0TC, ( u32 )&T1TC, ( u32 )&T2TC, ( u32 )&T3TC };
static const u32 tmr_pr[] = { ( u32 )&T0PR, ( u32 )&T1PR, ( u32 )&T2PR, ( u32 )&T3PR };
static const u32 tmr_pc[] = { ( u32 )&T0PC, ( u32 )&T1PC, ( u32 )&T2PC, ( u32 )&T3PC };
static const u32 tmr_mr1[] = { ( u32 )&T0MR1, ( u32 )&T1MR1, ( u32 )&T2MR1, ( u32 )&T3MR1 };
static const u32 tmr_mcr[] = { ( u32 )&T0MCR, ( u32 )&T1MCR, ( u32 )&T2MCR, ( u32 )&T3MCR };
static const u32 tmr_emr[] = { ( u32 )&T0EMR, ( u32 )&T1EMR, ( u32 )&T2EMR, ( u32 )&T3EMR };
// Timer register definitions
enum
{
TMR_ENABLE = 1,
TMR_RESET = 2
};
// Helper function: get timer clock
static u32 platform_timer_get_clock( unsigned id )
{
PREG TxPR = ( PREG )tmr_pr[ id ];
return Fpclk / ( *TxPR + 1 );
}
// Helper function: set timer clock
static u32 platform_timer_set_clock( unsigned id, u32 clock )
{
u32 div = Fpclk / clock, prevtc;
PREG TxPR = ( PREG )tmr_pr[ id ];
PREG TxPC = ( PREG )tmr_pc[ id ];
PREG TxTCR = ( PREG )tmr_tcr[ id ];
prevtc = *TxTCR;
*TxTCR = 0;
*TxPC = 0;
*TxPR = div - 1;
*TxTCR = prevtc;
return Fpclk / div;
}
static void int_handler_tmr()
{
T3IR = 1; // clear interrupt
cmn_virtual_timer_cb(); // handle virtual timers if they're present
cmn_systimer_periodic(); // handle the system timer
VICVectAddr = 0; // ACK interrupt
}
// Helper function: setup timers
static void platform_setup_timers()
{
unsigned i;
PREG TxTCR;
// Set base frequency to 1MHz, as we can't use a better resolution anyway
for( i = 0; i < 4; i ++ )
{
TxTCR = ( PREG )tmr_tcr[ i ];
*TxTCR = 0;
platform_timer_set_clock( i, 1000000ULL );
}
// Setup system timer
cmn_systimer_set_base_freq( 1000000 );
cmn_systimer_set_interrupt_freq( VTMR_FREQ_HZ );
// Setup virtual timers / system timer here
// Timer 3 is allocated for virtual timers and the system timer, nothing else
T3TCR = TMR_RESET;
T3MR0 = 1000000ULL / VTMR_FREQ_HZ - 1;
T3IR = 0xFF;
// Set interrupt handle and eanble timer interrupt (and global interrupts)
T3MCR = 0x03; // interrupt on match with MR0 and clear on match
install_irq( TIMER3_INT, int_handler_tmr, HIGHEST_PRIORITY );
platform_cpu_set_global_interrupts( PLATFORM_CPU_ENABLE );
// Start timer
T3TCR = TMR_ENABLE;
}
void platform_s_timer_delay( unsigned id, timer_data_type delay_us )
{
PREG TxTCR = ( PREG )tmr_tcr[ id ];
PREG TxTC = ( PREG )tmr_tc[ id ];
u32 last;
last = ( ( u64 )delay_us * platform_timer_get_clock( id ) ) / 1000000;
*TxTCR = TMR_ENABLE | TMR_RESET;
*TxTCR = TMR_ENABLE;
while( *TxTC < last );
}
timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
{
u32 res = 0;
PREG TxTCR = ( PREG )tmr_tcr[ id ];
PREG TxTC = ( PREG )tmr_tc[ id ];
switch( op )
{
case PLATFORM_TIMER_OP_START:
*TxTCR = TMR_ENABLE | TMR_RESET;
*TxTCR = TMR_ENABLE;
break;
case PLATFORM_TIMER_OP_READ:
res = *TxTC;
break;
case PLATFORM_TIMER_OP_SET_CLOCK:
res = platform_timer_set_clock( id, data );
break;
case PLATFORM_TIMER_OP_GET_CLOCK:
res = platform_timer_get_clock( id );
break;
case PLATFORM_TIMER_OP_GET_MAX_CNT:
res = 0xFFFFFFFF;
break;
}
return res;
}
int platform_s_timer_set_match_int( unsigned id, timer_data_type period_us, int type )
{
return PLATFORM_TIMER_INT_INVALID_ID;
}
u64 platform_timer_sys_raw_read()
{
return T3TC;
}
void platform_timer_sys_disable_int()
{
T3MCR = 0x02; // clear on match, no interrupt
}
void platform_timer_sys_enable_int()
{
T3MCR = 0x03; // interrupt on match with MR0 and clear on match
}
timer_data_type platform_timer_read_sys()
{
return cmn_systimer_get();
}
// *****************************************************************************
// ADC specific functions and variables
#ifdef BUILD_ADC
static const u32 adc_trig[] = { 6, 7, 0, 0 };
static const u32 adc_dr[] = { ( u32 )&AD0DR0, ( u32 )&AD0DR1, ( u32 )&AD0DR2, ( u32 )&AD0DR3,
( u32 )&AD0DR4, ( u32 )&AD0DR5, ( u32 )&AD0DR6, ( u32 )&AD0DR7 };
static const u8 pclk_div[] = { 4, 1, 2, 8};
int platform_adc_check_timer_id( unsigned id, unsigned timer_id )
{
return ( ( timer_id == 1 ) );
}
void platform_adc_stop( unsigned id )
{
elua_adc_ch_state *s = adc_get_ch_state( id );
elua_adc_dev_state *d = adc_get_dev_state( 0 );
s->op_pending = 0;
INACTIVATE_CHANNEL( d, id );
// If there are no more active channels, stop the sequencer
if( d->ch_active == 0 && d->running == 1 )
{
d->running = 0;
AD0CR &= 0xF8FFFF00; // stop ADC, disable channels
}
}
static void adc_int_handler()
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
elua_adc_ch_state *s = d->ch_state[ d->seq_ctr ];
u32 tmp, dreg_t;
tmp = AD0STAT; // Clear interrupt flag
//AD0INTEN = 0; // Disable generating interrupts
dreg_t = *( PREG )adc_dr[ s->id ];
if ( dreg_t & ( 1UL << 31 ) )
{
d->sample_buf[ d->seq_ctr ] = ( u16 )( ( dreg_t >> 6 ) & 0x3FF );
AD0CR &= 0xF8FFFF00; // stop ADC, disable channels
s->value_fresh = 1;
if ( s->logsmoothlen > 0 && s->smooth_ready == 0)
adc_smooth_data( s->id );
#if defined( BUF_ENABLE_ADC )
else if ( s->reqsamples > 1 )
{
buf_write( BUF_ID_ADC, s->id, ( t_buf_data* )s->value_ptr );
s->value_fresh = 0;
}
#endif
if ( adc_samples_available( s->id ) >= s->reqsamples && s->freerunning == 0 )
{
platform_adc_stop( s->id );
}
}
// Set up for next channel acquisition if we're still running
if( d->running == 1 )
{
// Prep next channel in sequence, if applicable
if( d->seq_ctr < ( d->seq_len - 1 ) )
d->seq_ctr++;
else if( d->seq_ctr == ( d->seq_len - 1 ) )
{
adc_update_dev_sequence( 0 );
d->seq_ctr = 0; // reset sequence counter if on last sequence entry
}
AD0CR |= ( 1ULL << d->ch_state[ d->seq_ctr ]->id );
//AD0INTEN |= ( 1ULL << d->ch_state[ d->seq_ctr ]->id );
if( d->clocked == 1 && d->seq_ctr == 0 ) // always use clock for first in clocked sequence
{
AD0CR |= ( adc_trig[ d->timer_id ] << 24 );
}
// Start next conversion if unclocked or if clocked and sequence index > 0
if( ( d->clocked == 1 && d->seq_ctr > 0 ) || d->clocked == 0 )
{
AD0CR |= ( 1ULL << 24 ); // Start conversion now
}
}
VICVectAddr = 0; // ACK interrupt
}
static void platform_setup_adcs()
{
unsigned id;
for( id = 0; id < NUM_ADC; id ++ )
adc_init_ch_state( id );
PCONP |= PCADC;
AD0CR = ( ( Fpclk / 4500000 - 1 ) << 8 ) | /* CLKDIV = Fpclk / 1000000 - 1 */
( 0 << 16 ) | /* BURST = 0, no BURST, software controlled */
( 0 << 17 ) | /* CLKS = 0, 11 clocks/10 bits */
( 1 << 21 ) | /* PDN = 1, normal operation */
( 0 << 22 ) | /* TEST1:0 = 00 */
( 0 << 24 ) | /* START = 0 A/D conversion stops */
( 0 << 27 ); /* EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion) */
// Default enables ADC interrupt only on global, switch to per-channel
//AD0INTEN &= ~( 1ULL << 8 );
install_irq( ADC0_INT, adc_int_handler, HIGHEST_PRIORITY );
}
// NOTE: On this platform, there is only one ADC, clock settings apply to the whole device
u32 platform_adc_set_clock( unsigned id, u32 frequency )
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
if ( frequency > 0 )
{
d->clocked = 1;
// Max Sampling Rate on LPC2468 is 200 kS/s
if ( frequency > 200000 )
frequency = 200000;
// Set clock to 1 MHz
platform_timer_set_clock( d->timer_id, 1000000ULL );
// Set match to period in uS
*( PREG )tmr_mr1[ d->timer_id ] = ( u32 )( ( 1000000ULL / ( frequency * 2 ) ) - 1 );
// Reset on match
*( PREG )tmr_mcr[ d->timer_id ] |= ( 1ULL << 4 );
// Don't stop on match
*( PREG )tmr_mcr[ d->timer_id ] &= ~( 1ULL << 5 );
// Set match channel to 1
*( PREG )tmr_emr[ d->timer_id ] |= ( 1ULL << 1 );
// Toggle output on match
*( PREG )tmr_emr[ d->timer_id ] |= ( 3ULL << 6 );
frequency = 1000000ULL / (*( PREG )tmr_mr1[ d->timer_id ] + 1);
}
else
d->clocked = 0;
return frequency;
}
static const u8 adc_ports[] = { 0, 0, 0, 0, 1, 1, 0, 0 };
static const u8 adc_pins[] = { 23, 24, 25, 26, 30, 31, 12, 13 };
static const u8 adc_funcs[] = { 1, 1, 1, 1, 3, 3, 3, 3 };
static const u32 pinsel_reg[] = { ( u32 )&PINSEL0, ( u32 )&PINSEL1, ( u32 )&PINSEL2,
( u32 )&PINSEL3, ( u32 )&PINSEL4, ( u32 )&PINSEL5,
( u32 )&PINSEL6, ( u32 )&PINSEL7, ( u32 )&PINSEL8,
( u32 )&PINSEL9, ( u32 )&PINSEL10 };
// Prepare Hardware Channel
int platform_adc_update_sequence( )
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
u8 seq_tmp;
unsigned id;
u32 pinnum, pinreg_idx;
for( seq_tmp = 0; seq_tmp < d->seq_len; seq_tmp++ )
{
id = d->ch_state[ seq_tmp ]->id;
pinnum = adc_pins[ id ];
pinreg_idx = 2 * adc_ports[ id ];
if ( pinnum >= 16 )
{
pinnum -= 16;
pinreg_idx++;
}
*( PREG )pinsel_reg[ pinreg_idx ] &= ~( 0x03UL << pinnum * 2 );
*( PREG )pinsel_reg[ pinreg_idx ] |= ( ( u32 )adc_funcs[ id ] << pinnum * 2 );
}
return PLATFORM_OK;
}
int platform_adc_start_sequence()
{
elua_adc_dev_state *d = adc_get_dev_state( 0 );
if( d->running != 1 )
{
adc_update_dev_sequence( 0 );
// Start sampling on first channel
d->seq_ctr = 0;
// Enable channel & interrupt on channel conversion
AD0CR |= ( 1ULL << d->ch_state[ d->seq_ctr ]->id );
//AD0INTEN |= ( 1ULL << d->ch_state[ d->seq_ctr ]->id );
d->running = 1;
if( d->clocked == 1 )
{
AD0CR |= ( adc_trig[ d->timer_id ] << 24 );
platform_s_timer_op( d->timer_id, PLATFORM_TIMER_OP_START, 0);
}
else
AD0CR |= ( 1ULL << 24 );
}
return PLATFORM_OK;
}
#endif // ifdef BUILD_ADC
// ****************************************************************************
// PWM functions
static const u32 pwm_tcr[] = { ( u32 )&PWM0TCR, ( u32 )&PWM1TCR };
static const u32 pwm_pr[] = { ( u32 )&PWM0PR, ( u32 )&PWM1PR };
static const u32 pwm_pc[] = { ( u32 )&PWM0PC, ( u32 )&PWM1PC };
static const u32 pwm_pcr[] = { ( u32 )&PWM0PCR, ( u32 )&PWM1PCR };
static const u32 pwm_mcr[] = { ( u32 )&PWM0MCR, ( u32 )&PWM1MCR };
static const u32 pwm_ler[] = { ( u32 )&PWM0LER, ( u32 )&PWM1LER };
static const u32 pwm_channels[ 2 ][ 6 ] =
{
{ ( u32 )&PWM0MR1, ( u32 )&PWM0MR2, ( u32 )&PWM0MR3, ( u32 )&PWM0MR4, ( u32 )&PWM0MR5, ( u32 )&PWM0MR6 },
{ ( u32 )&PWM1MR1, ( u32 )&PWM1MR2, ( u32 )&PWM1MR3, ( u32 )&PWM1MR4, ( u32 )&PWM1MR5, ( u32 )&PWM1MR6 },
};
// Timer register definitions
enum
{
PWM_ENABLE = 1,
PWM_RESET = 2,
PWM_MODE = 8,
PWM_ENABLE_1 = 1 << 9,
PWM_ENABLE_2 = 1 << 10,
PWM_ENABLE_3 = 1 << 11,
PWM_ENABLE_4 = 1 << 12,
PWM_ENABLE_5 = 1 << 13,
PWM_ENABLE_6 = 1 << 14,
};
// Get timer clock
u32 platform_pwm_get_clock( unsigned id )
{
unsigned pwmid = id / 6;
PREG PWMxPR = ( PREG )pwm_pr[ pwmid ];
return Fpclk / ( *PWMxPR + 1 );
}
// Set timer clock
u32 platform_pwm_set_clock( unsigned id, u32 clock )
{
u32 div = Fpclk / clock, prevtc;
unsigned pwmid = id / 6;
PREG PWMxPR = ( PREG )pwm_pr[ pwmid ];
PREG PWMxPC = ( PREG )pwm_pc[ pwmid ];
PREG PWMxTCR = ( PREG )pwm_tcr[ pwmid ];
prevtc = *PWMxTCR;
*PWMxTCR = 0;
*PWMxPC = 0;
*PWMxPR = div - 1;
*PWMxTCR = prevtc;
return Fpclk / div;
}
// Setup all PWM channels
static void platform_setup_pwm()
{
unsigned i;
PREG temp;
for( i = 0; i < 2; i ++ )
{
// Keep clock in reset, set PWM code
temp = ( PREG )pwm_tcr[ i ];
*temp = PWM_RESET;
// Set match mode (reset on MR0 match)
temp = ( PREG )pwm_mcr[ i ];
*temp = 0x02;
// Set base frequency to 1MHz
platform_pwm_set_clock( i * 6, 1000000 );
}
}
u32 platform_pwm_setup( unsigned id, u32 frequency, unsigned duty )
{
unsigned pwmid = id / 6, chid = id % 6;
PREG PWMxMR0 = pwmid == 0 ? ( PREG )&PWM0MR0 : ( PREG )&PWM1MR0;
PREG PWMxMRc = ( PREG )pwm_channels[ pwmid ][ chid ];
PREG PWMxLER = ( PREG )pwm_ler[ pwmid ];
u32 divisor;
divisor = platform_pwm_get_clock( id ) / frequency - 1;
*PWMxMR0 = divisor;
*PWMxMRc = ( divisor * duty ) / 100;
*PWMxLER = 1 | ( 1 << ( chid + 1 ) );
return platform_pwm_get_clock( id ) / divisor;
}
void platform_pwm_start( unsigned id )
{
unsigned pwmid = id / 6;
PREG PWMxTCR = ( PREG )pwm_tcr[ pwmid ];
PREG PWMxPCR = ( PREG )pwm_pcr[ pwmid ];
*PWMxPCR = PWM_ENABLE_1 | PWM_ENABLE_2 | PWM_ENABLE_3 | PWM_ENABLE_4 | PWM_ENABLE_5 | PWM_ENABLE_6;
*PWMxTCR = PWM_ENABLE | PWM_MODE;
}
void platform_pwm_stop( unsigned id )
{
unsigned pwmid = id / 6;
PREG PWMxTCR = ( PREG )pwm_tcr[ pwmid ];
PREG PWMxPCR = ( PREG )pwm_pcr[ pwmid ];
*PWMxPCR = 0;
*PWMxTCR = PWM_RESET;
}

View File

@ -0,0 +1,44 @@
// Platform-wide configuration file, included by platform_conf.h
#ifndef __PLATFORM_GENERIC_H__
#define __PLATFORM_GENERIC_H__
#define PLATFORM_HAS_SYSTIMER
// If virtual timers are enabled, the last timer will be used only for them
#if VTMR_NUM_TIMERS > 0
#undef NUM_TIMER
#define NUM_TIMER 3
#endif
// *****************************************************************************
// CPU constants that should be exposed to the eLua "cpu" module
#define PINSEL_BASE_ADDR 0xE002C000
#define IO_PINSEL0 ( PINSEL_BASE_ADDR + 0x00 )
#define IO_PINSEL1 ( PINSEL_BASE_ADDR + 0x04 )
#define IO_PINSEL2 ( PINSEL_BASE_ADDR + 0x08 )
#define IO_PINSEL3 ( PINSEL_BASE_ADDR + 0x0C )
#define IO_PINSEL4 ( PINSEL_BASE_ADDR + 0x10 )
#define IO_PINSEL5 ( PINSEL_BASE_ADDR + 0x14 )
#define IO_PINSEL6 ( PINSEL_BASE_ADDR + 0x18 )
#define IO_PINSEL7 ( PINSEL_BASE_ADDR + 0x1C )
#define IO_PINSEL8 ( PINSEL_BASE_ADDR + 0x20 )
#define IO_PINSEL9 ( PINSEL_BASE_ADDR + 0x24 )
#define IO_PINSEL10 ( PINSEL_BASE_ADDR + 0x28 )
#define PLATFORM_CPU_CONSTANTS_PLATFORM\
_C( IO_PINSEL0 ),\
_C( IO_PINSEL1 ),\
_C( IO_PINSEL2 ),\
_C( IO_PINSEL3 ),\
_C( IO_PINSEL4 ),\
_C( IO_PINSEL5 ),\
_C( IO_PINSEL6 ),\
_C( IO_PINSEL7 ),\
_C( IO_PINSEL8 ),\
_C( IO_PINSEL9 ),\
_C( IO_PINSEL10 ),
#endif // #ifndef __PLATFORM_GENERIC_H__

View File

@ -0,0 +1,263 @@
// LPC23xx interrupt support
// Generic headers
#include "platform.h"
#include "platform_conf.h"
#include "elua_int.h"
#include "common.h"
// Platform-specific headers
#include "irq.h"
#include "LPC23xx.h"
#include "target.h"
#include "uart.h"
// ****************************************************************************
// Interrupt handlers
// ----------------------------------------------------------------------------
// GPIO
static PREG const posedge_status[] = { ( PREG )&IO0_INT_STAT_R, ( PREG )&IO2_INT_STAT_R };
static PREG const negedge_status[] = { ( PREG )&IO0_INT_STAT_F, ( PREG )&IO2_INT_STAT_F };
static PREG const intclr_regs[] = { ( PREG )&IO0_INT_CLR, ( PREG )&IO2_INT_CLR };
#define EINT3_BIT 3
// EINT3 (INT_GPIO) interrupt handler
static void int_handler_eint3()
{
elua_int_id id = ELUA_INT_INVALID_INTERRUPT;
pio_code resnum = 0;
int pidx, pin;
EXTINT |= 1 << EINT3_BIT; // clear interrupt
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( *posedge_status[ pidx ] )
{
id = INT_GPIO_POSEDGE;
pin = intlog2( *posedge_status[ pidx ] );
}
else
{
id = INT_GPIO_NEGEDGE;
pin = intlog2( *negedge_status[ pidx ] );
}
resnum = PLATFORM_IO_ENCODE( pidx * 2, pin, PLATFORM_IO_ENC_PIN );
*intclr_regs[ pidx ] = 1 << pin;
// Run the interrupt through eLua
cmn_int_handler( id, resnum );
VICVectAddr = 0; // ACK interrupt
}
// ----------------------------------------------------------------------------
// UART
static PREG const uart_ier[] = { ( PREG )&U0IER, ( PREG )&U1IER, ( PREG )&U2IER, ( PREG )&U3IER };
static PREG const uart_iir[] = { ( PREG )&U0IIR, ( PREG )&U1IIR, ( PREG )&U2IIR, ( PREG )&U3IIR };
// Common UART interrupt handler
static void uart_rx_common_handler( elua_int_resnum resnum )
{
cmn_int_handler( INT_UART_RX, resnum );
VICVectAddr = 0;
}
// Interrupt handlers for individual UARTs
static void int_handler_uart0()
{
uart_rx_common_handler( 0 );
}
static void int_handler_uart1()
{
uart_rx_common_handler( 1 );
}
static void int_handler_uart2()
{
uart_rx_common_handler( 2 );
}
static void int_handler_uart3()
{
uart_rx_common_handler( 3 );
}
// ****************************************************************************
// GPIO helper functions
static PREG const posedge_regs[] = { ( PREG )&IO0_INT_EN_R, NULL, ( PREG )&IO2_INT_EN_R };
static PREG const negedge_regs[] = { ( PREG )&IO0_INT_EN_F, NULL, ( PREG )&IO0_INT_EN_F };
static int gpioh_get_int_status( elua_int_id id, elua_int_resnum resnum )
{
int port, pin;
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
return *posedge_regs[ port ] & ( 1 << pin );
else
return *negedge_regs[ port ] & ( 1 << pin );
return 0;
}
static int gpioh_set_int_status( elua_int_id id, elua_int_resnum resnum, int status )
{
int crt_status = gpioh_get_int_status( id, resnum );
int port, pin;
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
{
if( status == PLATFORM_CPU_ENABLE )
*posedge_regs[ port ] |= 1 << pin;
else
*posedge_regs[ port ] &= ~( 1 << pin );
}
else
{
if( status == PLATFORM_CPU_ENABLE )
*negedge_regs[ port ] |= 1 << pin;
else
*negedge_regs[ port ] &= ~( 1 << pin );
}
EXTINT |= 1 << EINT3_BIT;
return crt_status;
}
static int gpioh_get_flag( elua_int_id id, elua_int_resnum resnum, int clear )
{
int pidx;
int flag = 0;
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( id == INT_GPIO_POSEDGE && ( *posedge_status[ pidx ] && ( 1 << resnum ) ) )
flag = 1;
else if( id == INT_GPIO_NEGEDGE && ( *negedge_status[ pidx ] && ( 1 << resnum ) ) )
flag = 1;
if( flag && clear )
*intclr_regs[ pidx ] = 1 << resnum;
return flag;
}
// ****************************************************************************
// Interrupt: INT_GPIO_POSEDGE
static int int_gpio_posedge_set_status( elua_int_resnum resnum, int status )
{
return gpioh_set_int_status( INT_GPIO_POSEDGE, resnum, status );
}
static int int_gpio_posedge_get_status( elua_int_resnum resnum )
{
return gpioh_get_int_status( INT_GPIO_POSEDGE, resnum );
}
static int int_gpio_posedge_get_flag( elua_int_resnum resnum, int clear )
{
return gpioh_get_flag( INT_GPIO_POSEDGE, resnum, clear );
}
// ****************************************************************************
// Interrupt: INT_GPIO_NEGEDGE
static int int_gpio_negedge_set_status( elua_int_resnum resnum, int status )
{
return gpioh_set_int_status( INT_GPIO_NEGEDGE, resnum, status );
}
static int int_gpio_negedge_get_status( elua_int_resnum resnum )
{
return gpioh_get_int_status( INT_GPIO_NEGEDGE, resnum );
}
static int int_gpio_negedge_get_flag( elua_int_resnum resnum, int clear )
{
return gpioh_get_flag( INT_GPIO_NEGEDGE, resnum, clear );
}
// ****************************************************************************
// Interrupt: INT_TMR_MATCH
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
{
return PLATFORM_INT_BAD_RESNUM;
}
static int int_tmr_match_get_status( elua_int_resnum resnum )
{
return PLATFORM_INT_BAD_RESNUM;
}
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
{
return PLATFORM_INT_BAD_RESNUM;
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
PREG UxIER = uart_ier[ resnum ];
return ( *UxIER & IER_RBR ) ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
PREG UxIER = uart_ier[ resnum ];
int prev = int_uart_rx_get_status( resnum );
if( status == PLATFORM_CPU_ENABLE )
*UxIER |= IER_RBR;
else
*UxIER &= ~IER_RBR;
return prev;
}
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
{
PREG UxIIR = uart_iir[ resnum ];
// 'clear' is not needed here, the interrupt will be cleared when reading the RBR register
( void )clear;
if( ( *UxIIR & IIR_PEND ) == 0 )
return ( ( *UxIIR >> 1 ) & 0x07 ) == IIR_RDA;
return 0;
}
// ****************************************************************************
// Interrupt initialization
typedef void ( *p_handler )();
void platform_int_init()
{
install_irq( EINT3_INT, int_handler_eint3, HIGHEST_PRIORITY + 1 );
install_irq( UART0_INT, int_handler_uart0, HIGHEST_PRIORITY + 2 );
install_irq( UART1_INT, int_handler_uart1, HIGHEST_PRIORITY + 3 );
install_irq( UART2_INT, int_handler_uart2, HIGHEST_PRIORITY + 4 );
install_irq( UART3_INT, int_handler_uart3, HIGHEST_PRIORITY + 5 );
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_ints.h!
const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
{
{ int_gpio_posedge_set_status, int_gpio_posedge_get_status, int_gpio_posedge_get_flag },
{ int_gpio_negedge_set_status, int_gpio_negedge_get_status, int_gpio_negedge_get_flag },
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag },
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag }
};

View File

@ -0,0 +1,15 @@
// This header lists all interrupts defined for this platform
#ifndef __PLATFORM_INTS_H__
#define __PLATFORM_INTS_H__
#include "elua_int.h"
#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID
#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 )
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 )
#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 )
#define INT_ELUA_LAST INT_UART_RX
#endif // #ifndef __PLATFORM_INTS_H__

View File

@ -0,0 +1,11 @@
// Stack size definitions
#ifndef __STACKS_H__
#define __STACKS_H__
#define STACK_SIZE_USR 0x00000400
#define STACK_SIZE_IRQ 0x00000100
#define STACK_SIZE_TOTAL ( STACK_SIZE_USR + STACK_SIZE_IRQ )
#endif

View File

@ -0,0 +1,128 @@
#include "stacks.h"
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
#define ARM_MODE_USR 0x10
#define ARM_MODE_FIQ 0x11
#define ARM_MODE_IRQ 0x12
#define ARM_MODE_SVC 0x13
#define ARM_MODE_ABT 0x17
#define ARM_MODE_UND 0x1B
#define ARM_MODE_SYS 0x1F
#define I_BIT 0x80
#define F_BIT 0x40
#define RAM_Base 0x40000000
#define RAM_Size (32 * 1024) // [TODO] make this 96k?
#define Top_Stack (RAM_Base + RAM_Size)
#define VectorAddress 0xFFFFFF00
//------------------------------------------------------------------------------
// Startup routine
//------------------------------------------------------------------------------
.align 4
.arm
/* Exception vectors
*******************/
.section .vectors, "a"
resetVector:
ldr pc, =resetHandler /* Reset */
undefVector:
b undefVector /* Undefined instruction */
swiVector:
b swiVector /* Software interrupt */
prefetchAbortVector:
b prefetchAbortVector /* Prefetch abort */
dataAbortVector:
b dataAbortVector /* Data abort */
reservedVector:
b reservedVector /* Reserved for future use */
irqVector:
b irqHandler /* Generic IRQ handler */
fiqVector:
b fiqVector /* Fast interrupt */
//------------------------------------------------------------------------------
/// IRQ handler
//------------------------------------------------------------------------------
irqHandler:
sub lr, lr ,#4
stmfd sp!, {r0-r3, r12, lr}
ldr r0, =VectorAddress
ldr r0, [r0]
mov lr, pc
bx r0
ldmfd sp!, {r0-r3, r12, pc}^
//------------------------------------------------------------------------------
/// Initializes the chip and branches to the main() function.
//------------------------------------------------------------------------------
.section .text
.global entry
.extern main
.extern TargetResetInit
entry:
resetHandler:
/* Setup stacks for each mode */
ldr r0, =Top_Stack
/* Set IRQ Mode Stack & Pointer */
msr CPSR_c, #ARM_MODE_IRQ|I_BIT|F_BIT
mov r13, r0
sub r0, r0, #STACK_SIZE_IRQ
/* Set SVC Mode Stack & Pointer - leave interrupts enabled */
msr CPSR_c, #ARM_MODE_SVC|F_BIT
mov r13, r0
sub r0, r0, #STACK_SIZE_USR
/* Perform low-level initialization of the chip using LowLevelInit() */
/* Initialize the relocate segment */
ldr r0, =_efixed
ldr r1, =_srelocate
ldr r2, =_erelocate
CopyROMtoRAM:
cmp r1, r2
ldrcc r3, [r0], #4
strcc r3, [r1], #4
bcc CopyROMtoRAM
/* Clear the zero segment */
ldr r0, =_szero
ldr r1, =_ezero
mov r2, #0
ZeroBSS:
cmp r0, r1
strcc r2, [r0], #4
bcc ZeroBSS
/* Call external initialization code */
bl TargetResetInit
/* Branch to main()
******************/
ldr r0, =main
mov lr, pc
bx r0
/* Loop indefinitely when program is finished */
forever:
b forever
.end

View File

@ -0,0 +1,197 @@
/*****************************************************************************
* target.c: Target C file for NXP LPC23xx/24xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.07.13 ver 1.00 Prelimnary version, first Release
*
*****************************************************************************/
#include "LPC23xx.h"
#include "type.h"
#include "irq.h"
#include "target.h"
/******************************************************************************
** Function name: TargetInit
**
** Descriptions: Initialize the target board; it is called in a necessary
** place, change it as needed
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void TargetInit(void)
{
/* Add your codes here */
return;
}
/******************************************************************************
** Function name: GPIOResetInit
**
** Descriptions: Initialize the target board before running the main()
** function; User may change it as needed, but may not
** deleted it.
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void GPIOResetInit( void )
{
/* Reset all GPIO pins to default: primary function */
PINSEL0 = 0x00000000;
PINSEL1 = 0x00000000;
PINSEL2 = 0x00000000;
PINSEL3 = 0x00000000;
PINSEL4 = 0x00000000;
PINSEL5 = 0x00000000;
PINSEL6 = 0x00000000;
PINSEL7 = 0x00000000;
PINSEL8 = 0x00000000;
PINSEL9 = 0x00000000;
PINSEL10 = 0x00000000;
IODIR0 = 0x00000000;
IODIR1 = 0x00000000;
IOSET0 = 0x00000000;
IOSET1 = 0x00000000;
FIO0DIR = 0x00000000;
FIO1DIR = 0x00000000;
FIO2DIR = 0x00000000;
FIO3DIR = 0x00000000;
FIO4DIR = 0x00000000;
FIO0SET = 0x00000000;
FIO1SET = 0x00000000;
FIO2SET = 0x00000000;
FIO3SET = 0x00000000;
FIO4SET = 0x00000000;
return;
}
/******************************************************************************
** Function name: ConfigurePLL
**
** Descriptions: Configure PLL switching to main OSC instead of IRC
** at power up and wake up from power down.
** This routine is used in TargetResetInit() and those
** examples using power down and wake up such as
** USB suspend to resume, ethernet WOL, and power management
** example
** parameters: None
** Returned value: None
**
******************************************************************************/
void ConfigurePLL ( void )
{
DWORD MValue, NValue;
if ( PLLSTAT & (1 << 25) )
{
PLLCON = 1; /* Enable PLL, disconnected */
PLLFEED = 0xaa;
PLLFEED = 0x55;
}
PLLCON = 0; /* Disable PLL, disconnected */
PLLFEED = 0xaa;
PLLFEED = 0x55;
SCS |= 0x20; /* Enable main OSC */
while( !(SCS & 0x40) ); /* Wait until main OSC is usable */
CLKSRCSEL = 0x1; /* select main OSC, 12MHz, as the PLL clock source */
PLLCFG = PLL_MValue | (PLL_NValue << 16);
PLLFEED = 0xaa;
PLLFEED = 0x55;
PLLCON = 1; /* Enable PLL, disconnected */
PLLFEED = 0xaa;
PLLFEED = 0x55;
CCLKCFG = CCLKDivValue; /* Set clock divider */
#if USE_USB
USBCLKCFG = USBCLKDivValue; /* usbclk = 288 MHz/6 = 48 MHz */
#endif
while ( ((PLLSTAT & (1 << 26)) == 0) ); /* Check lock bit status */
MValue = PLLSTAT & 0x00007FFF;
NValue = (PLLSTAT & 0x00FF0000) >> 16;
while ((MValue != PLL_MValue) && ( NValue != PLL_NValue) );
PLLCON = 3; /* enable and connect */
PLLFEED = 0xaa;
PLLFEED = 0x55;
while ( ((PLLSTAT & (1 << 25)) == 0) ); /* Check connect bit status */
}
/******************************************************************************
** Function name: TargetResetInit
**
** Descriptions: Initialize the target board before running the main()
** function; User may change it as needed, but may not
** deleted it.
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void TargetResetInit(void)
{
#ifdef __DEBUG_RAM
MEMMAP = 0x2; /* remap to internal RAM */
#endif
#ifdef __DEBUG_FLASH
MEMMAP = 0x1; /* remap to internal flash */
#endif
#if USE_USB
PCONP |= 0x80000000; /* Turn On USB PCLK */
#endif
/* Configure PLL, switch from IRC to Main OSC */
ConfigurePLL();
/* Set system timers for each component */
#if (Fpclk / (Fcclk / 4)) == 1
PCLKSEL0 = 0x00000000; /* PCLK is 1/4 CCLK */
PCLKSEL1 = 0x00000000;
#endif
#if (Fpclk / (Fcclk / 4)) == 2
PCLKSEL0 = 0xAAAAAAAA; /* PCLK is 1/2 CCLK */
PCLKSEL1 = 0xAAAAAAAA;
#endif
#if (Fpclk / (Fcclk / 4)) == 4
PCLKSEL0 = 0x55555555; /* PCLK is the same as CCLK */
PCLKSEL1 = 0x55555555;
#endif
/* Set memory accelerater module*/
MAMCR = 0;
#if Fcclk < 20000000
MAMTIM = 1;
#else
#if Fcclk < 40000000
MAMTIM = 2;
#else
MAMTIM = 3;
#endif
#endif
MAMCR = 2;
GPIOResetInit();
init_VIC();
}
/******************************************************************************
** End Of File
******************************************************************************/

View File

@ -0,0 +1,169 @@
/*****************************************************************************
* target.h: Header file for NXP LPC23xx/24xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.09.20 ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
#ifndef __TARGET_H
#define __TARGET_H
#ifdef __cplusplus
extern "C" {
#endif
/* Only choose one of them below, by default, it's Keil MCB2300 */
/*#define ENG_BOARD_LPC24XX 0
#define KEIL_BOARD_LPC23XX 1
#define EA_BOARD_LPC24XX 0
#define IAR_BOARD_LPC23XX 0*/
/* On EA and IAR boards, they use Micrel PHY.
on ENG and KEIL boards, they use National PHY */
/*#define NATIONAL_PHY 1
#define MICREL_PHY 2*/
/* If USB device is used, CCO will be 288Mhz( divided by 6) or 384Mhz( divided by 8)
to get precise USB clock 48Mhz. If USB is not used, you set any clock you want
but make sure the divider of the CCO should be an even number. If you want to
use USB, change "define USE_USB" from 0 to 1 */
#define USE_USB 0
/* PLL Setting Table Matrix */
/*
Main Osc. CCLKCFG Fcco Fcclk M N
12Mhz 29 300Mhz 10Mhz 24 1
12Mhz 35 360Mhz 10Mhz 14 0
12Mhz 27 336Mhz 12Mhz 13 0
12Mhz 17 360Mhz 20Mhz 14 0
12Mhz 13 336Mhz 24Mhz 13 0
12Mhz 11 300Mhz 25Mhz 24 1
12Mhz 9 300Mhz 30Mhz 24 1
12Mhz 11 360Mhz 30Mhz 14 0
12Mhz 9 320Mhz 32Mhz 39 2
12Mhz 9 350Mhz 35Mhz 174 11
12Mhz 7 312Mhz 39Mhz 12 0
12Mhz 7 360Mhz 45Mhz 14 0
12Mhz 5 300Mhz 50Mhz 24 1
12Mhz 5 312Mhz 52Mhz 12 0
12Mhz 5 336Mhz 56Mhz 13 0
12Mhz 3 300Mhz 75Mhz 24 1
12Mhz 3 312Mhz 78Mhz 12 0
12Mhz 3 320Mhz 80Mhz 39 2
12Mhz 3 336Mhz 84Mhz 13 0
*/
/* These are limited number of Fcco configuration for
USB communication as the CPU clock and USB clock shares
the same PLL. The USB clock needs to be multiple of
48Mhz. */
#if USE_USB /* 1 is USB, 0 is non-USB related */
/* Fcck = 48Mhz, Fosc = 288Mhz, and USB 48Mhz */
#define PLL_MValue 11
#define PLL_NValue 0
#define CCLKDivValue 5
#define USBCLKDivValue 5
/* System configuration: Fosc, Fcclk, Fcco, Fpclk must be defined */
/* PLL input Crystal frequence range 4KHz~20MHz. */
#define Fosc 12000000
/* System frequence,should be less than 80MHz. */
#define Fcclk 48000000
#define Fcco 288000000
#else // #if USE_USB
// [TODO]: use the PLL calculator XLS to increase frequency a bit
/* Fcck = 60Mhz, Fosc = 360Mhz, USB can't be divided into 48Mhz
in this case, so USBCLKDivValue is not needed. */
#if 0 // 60MHz
#define PLL_MValue 14
#define PLL_NValue 0
#define CCLKDivValue 5
#define Fcclk 60000000ULL
#else // 72MHz
#define PLL_MValue 14
#define PLL_NValue 0
#define CCLKDivValue 4
#define Fcclk 72000000ULL
#endif
/* System configuration: Fosc, Fcclk, Fcco, Fpclk must be defined */
/* PLL input Crystal frequence range 4KHz~20MHz. */
#define Fosc 12000000
/* System frequence,should be less than 72MHz. */
#define Fcco 360000000
#endif
/* APB clock frequence , must be 1/2/4 multiples of ( Fcclk/4 ). */
/* If USB is enabled, the minimum APB must be greater than 16Mhz */
#if USE_USB
#define Fpclk (Fcclk / 2)
#else
#define Fpclk (Fcclk / 4)
#endif
#define Fpclk_MHz (Fpclk / 1000000)
#define Fpclk_UART (Fcclk)
#define SYS_FREQ (Fcclk / 1000000)
#ifdef ELUA_BOARD_ELUAPUC
#if SYS_FREQ == (72)
#define EMC_PERIOD 13.88888888 // 72MHz
#elif SYS_FREQ == (60)
#define EMC_PERIOD 16.6 // 60MHz
#elif SYS_FREQ == (57)
#define EMC_PERIOD 17.4 // 57.6MHz
#elif SYS_FREQ == (48)
#define EMC_PERIOD 20.8 // 48MHz
#elif SYS_FREQ == (36)
#define EMC_PERIOD 27.8 // 36MHz
#elif SYS_FREQ == (24)
#define EMC_PERIOD 41.7 // 24MHz
#else
#error Frequency not defined
#endif
#define SDRAM_REFRESH 15625 //max 64ms
#define SDRAM_TRP 18 //
#define SDRAM_TRAS 42
#define SDRAM_TAPR 2
#define SDRAM_TWR 2
#define SDRAM_TDAL (SDRAM_TWR+P2C(SDRAM_TRP))
#define SDRAM_TRC 60 //samsung 65 micron 66
#define SDRAM_TRFC 60
#define SDRAM_TXSR 70
#define SDRAM_TRRD 12
#define SDRAM_TMRD 2
#endif
/******************************************************************************
** Function name: TargetInit
**
** Descriptions: Initialize the target board; it is called in a
** necessary place, change it as needed
**
** parameters: None
** Returned value: None
**
******************************************************************************/
extern void TargetInit(void);
extern void ConfigurePLL( void );
extern void TargetResetInit(void);
#ifdef __cplusplus
}
#endif
#endif /* end __TARGET_H */
/******************************************************************************
** End Of File
******************************************************************************/

View File

@ -0,0 +1,29 @@
#ifndef __TYPE_H__
#define __TYPE_H__
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned long long u64;
typedef signed long long s64;
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned int BOOL;
typedef volatile unsigned long* PREG;
#endif

View File

@ -0,0 +1,59 @@
/*****************************************************************************
* uart.h: Header file for NXP LPC23xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.09.01 ver 1.00 Prelimnary version, first Release
*
* Modified by BogdanM for eLua
******************************************************************************/
#ifndef __UART_H
#define __UART_H
#include "type.h"
#define IER_RBR 0x01
#define IER_THRE 0x02
#define IER_RLS 0x04
#define IIR_PEND 0x01
#define IIR_RLS 0x03
#define IIR_RDA 0x02
#define IIR_CTI 0x06
#define IIR_THRE 0x01
#define LSR_RDR 0x01
#define LSR_OE 0x02
#define LSR_PE 0x04
#define LSR_FE 0x08
#define LSR_BI 0x10
#define LSR_THRE 0x20
#define LSR_TEMT 0x40
#define LSR_RXFE 0x80
// UART setup constants
enum
{
UART_DATABITS_5 = 0,
UART_DATABITS_6 = 1,
UART_DATABITS_7 = 2,
UART_DATABITS_8 = 3,
UART_STOPBITS_1 = 0,
UART_STOPBITS_2 = 4,
UART_PARITY_ENABLE = 8,
UART_PARITY_ODD = 0,
UART_PARITY_EVEN = 1 << 4,
UART_DLAB_ENABLE = 1 << 7,
UART_FIFO_ENABLE = 1,
UART_RXFIFO_RESET = 2,
UART_TXFIFO_RESET = 4
};
#endif /* end __UART_H */
/*****************************************************************************
** End Of File
******************************************************************************/

View File

@ -0,0 +1,52 @@
// CPU definition file for STM32F411RE
#ifndef __CPU_STM32F411RE_H__
#define __CPU_STM32F411RE_H__
#include "type.h"
#include "stacks.h"
#include "platform_ints.h"
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 5
#define NUM_SPI 3
#define NUM_UART 3
#define NUM_TIMER 12
#define NUM_PHYS_TIMER 12
#define NUM_PWM 4
#define NUM_ADC 18
#define NUM_CAN 0
#define ADC_BIT_RESOLUTION 12
u32 platform_s_cpu_get_frequency();
#define CPU_FREQUENCY platform_s_cpu_get_frequency()
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX 'A'
// Pins per port configuration:
// #define PIO_PINS_PER_PORT (n) if each port has the same number of pins, or
// #define PIO_PIN_ARRAY { n1, n2, ... } to define pins per port in an array
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 16
// Internal memory data
#define INTERNAL_SRAM_BASE 0x20000000
#define INTERNAL_SRAM_SIZE ( 128 * 1024 )
#define INTERNAL_RAM1_FIRST_FREE end
#define INTERNAL_RAM1_LAST_FREE ( INTERNAL_SRAM_BASE + INTERNAL_SRAM_SIZE - STACK_SIZE_TOTAL -1 )
// Internal Flash data
#define INTERNAL_FLASH_SIZE ( 512 * 1024 )
#define INTERNAL_FLASH_SECTOR_ARRAY { 16384, 16384, 16384, 16384, 65536, 131072, 131072, 131072 }
#define INTERNAL_FLASH_START_ADDRESS 0x08000000
// Interrupt list for this CPU
#define PLATFORM_CPU_CONSTANTS_INTS\
_C( INT_GPIO_POSEDGE ), \
_C( INT_GPIO_NEGEDGE ), \
_C( INT_TMR_MATCH ), \
_C( INT_UART_RX ),
#endif // #ifndef __CPU_STM32F411RE_H__