diff --git a/u8g_arm.c b/u8g_arm.c new file mode 100644 --- /dev/null +++ b/u8g_arm.c @@ -0,0 +1,536 @@ +/* + + u8g_arm.c + + The following delay procedures must be implemented for u8glib. This is done in this file: + + void u8g_Delay(uint16_t val) Delay by "val" milliseconds + void u8g_MicroDelay(void) Delay be one microsecond + void u8g_10MicroDelay(void) Delay by 10 microseconds + + Additional requirements: + + SysTick must be enabled, but SysTick IRQ is not required. Any LOAD values are fine, + it is prefered to have at least 1ms + Example: + SysTick->LOAD = (SystemCoreClock/1000UL*(unsigned long)SYS_TICK_PERIOD_IN_MS) - 1; + SysTick->VAL = 0; + SysTick->CTRL = 7; // enable, generate interrupt (SysTick_Handler), do not divide by 2 +*/ + +#include "u8g_arm.h" + + +/*========================================================================*/ +/* system clock setup for LPC122x */ + +uint32_t SystemCoreClock = 12000000; + +/* activate PLL for the int. RC osc. Assumes the IRC is already running */ +/* this procedure is not required for u8glib, but can be called from the init code */ + void init_system_clock(void) + { + + /* do some simple startup tasks */ + LPC_SYSCON->SYSMEMREMAP = 2; + LPC_WWDT->MOD = 0; /* disable watchdog */ + LPC_SYSCON->INTNMI = 0x03f; /* disable NMI */ + + + /* setup 24MHz for the LPC122x (does not require additional wait states for the flash) */ + + /* oscillator controll registor, no change needed for int. RC osc. */ + LPC_SYSCON->SYSOSCCTRL = 0; /* no bypass (bit 0), low freq range (bit 1), reset value is also 0 */ + + LPC_SYSCON->SYSPLLCLKSEL = 0; /* select PLL source, 0: IRC, 1: Sys osc */ + LPC_SYSCON->SYSPLLCLKUEN = 0; /* confirm change by writing 0 and 1 to SYSPLLCLKUEN */ + LPC_SYSCON->SYSPLLCLKUEN = 1; + + LPC_SYSCON->SYSPLLCTRL = 1 | (3 << 5); /* 48 Mhz, m = 2, p = 4 */ + LPC_SYSCON->PDRUNCFG &= ~(1UL<<7); /* power-up PLL */ + + while (!(LPC_SYSCON->SYSPLLSTAT & 1)) + ; /* wait for PLL lock */ + + LPC_SYSCON->MAINCLKSEL = 3; /* select PLL for main clock */ + LPC_SYSCON->MAINCLKUEN = 0; /* confirm change by writing 0 and 1 to MAINCLKUEN */ + LPC_SYSCON->MAINCLKUEN = 1; + + LPC_SYSCON->SYSAHBCLKDIV = 1; /* set AHB clock divider to 1 */ + + SystemCoreClock = 24000000UL; +} + +/*========================================================================*/ +/* Generic ARM delay procedure, based on the system timer (SysTick) */ + +/* + Delay by the provided number of system ticks. + The delay must be smaller than the RELOAD value. + This delay has an imprecision of about +/- 20 system ticks. +*/ +static void _delay_system_ticks_sub(uint32_t sys_ticks) +{ + uint32_t start_val, end_val, curr_val; + uint32_t load; + + start_val = SysTick->VAL; + start_val &= 0x0ffffffUL; + end_val = start_val; + + if ( end_val < sys_ticks ) + { + /* check, if the operation after this if clause would lead to a negative result */ + /* if this would be the case, then add the reload value first */ + load = SysTick->LOAD; + load &= 0x0ffffffUL; + end_val += load; + } + /* counter goes towards zero, so end_val is below start value */ + end_val -= sys_ticks; + + + /* wait until interval is left */ + if ( start_val >= end_val ) + { + for(;;) + { + curr_val = SysTick->VAL; + curr_val &= 0x0ffffffUL; + if ( curr_val <= end_val ) + break; + if ( curr_val > start_val ) + break; + } + } + else + { + for(;;) + { + curr_val = SysTick->VAL; + curr_val &= 0x0ffffffUL; + if ( curr_val <= end_val && curr_val > start_val ) + break; + } + } +} + +/* + Delay by the provided number of system ticks. + Any values between 0 and 0x0ffffffff are allowed. +*/ +void delay_system_ticks(uint32_t sys_ticks) +{ + uint32_t load4; + load4 = SysTick->LOAD; + load4 &= 0x0ffffffUL; + load4 >>= 2; + + while ( sys_ticks > load4 ) + { + sys_ticks -= load4; + _delay_system_ticks_sub(load4); + } + _delay_system_ticks_sub(sys_ticks); +} + +/* + Delay by the provided number of micro seconds. + Limitation: "us" * System-Freq in MHz must now overflow in 32 bit. + Values between 0 and 1.000.000 (1 second) are ok. +*/ +void delay_micro_seconds(uint32_t us) +{ + uint32_t sys_ticks; + + sys_ticks = SystemCoreClock; + sys_ticks /=1000000UL; + sys_ticks *= us; + delay_system_ticks(sys_ticks); +} + +/*========================================================================*/ +/* generic gpio procedures (not required for u8glib) */ + +struct _lpc_pin_info_struct +{ + uint16_t offset; + uint8_t iocon_gpio_value_no_pullup; + uint8_t iocon_gpio_value_pullup; /* identical to iocon_gpio_value_no_pullup if there is no pullup */ +}; +typedef struct _lpc_pin_info_struct lpc_pin_info_struct; + +const lpc_pin_info_struct lpc11xx_pin_info[] = +{ + { offsetof(LPC_IOCON_Type,PIO0_0), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_1), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_2), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_3), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_4), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_5), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_6), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_7), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_8), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_9), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_10), 128, 128}, /* no pullup available */ + { offsetof(LPC_IOCON_Type,PIO0_11), 128, 128}, /* no pullup available */ + { offsetof(LPC_IOCON_Type,PIO0_12), 128, 128+16}, + { offsetof(LPC_IOCON_Type,RESET_PIO0_13), 128+16, 128+16}, /* reset pin, disallow GPIO here, always keep pullup */ + { offsetof(LPC_IOCON_Type,PIO0_14), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_15), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_16), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_17), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_18), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_19), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_20), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_21), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_22), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_23), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_24), 128, 128+16}, + { offsetof(LPC_IOCON_Type,SWDIO_PIO0_25), 128+6, 128+16+6}, + { offsetof(LPC_IOCON_Type,SWCLK_PIO0_26), 128+6, 128+16+6}, + { offsetof(LPC_IOCON_Type,PIO0_27), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_28), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO0_29), 128, 128+16}, + { offsetof(LPC_IOCON_Type,R_PIO0_30), 128+1, 128+16+1}, + { offsetof(LPC_IOCON_Type,R_PIO0_31), 128+1, 128+16+1}, + + { offsetof(LPC_IOCON_Type,R_PIO1_0), 128+1, 128+16+1}, + { offsetof(LPC_IOCON_Type,R_PIO1_1), 128+1, 128+16+1}, + { offsetof(LPC_IOCON_Type,PIO1_2), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO1_3), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO1_4), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO1_5), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO1_6), 128, 128+16}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + + { offsetof(LPC_IOCON_Type,PIO2_0), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_1), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_2), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_3), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_4), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_5), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_6), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_7), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_8), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_9), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_10), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_11), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_12), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_13), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_14), 128, 128+16}, + { offsetof(LPC_IOCON_Type,PIO2_15), 128, 128+16}, + + +}; + +LPC_GPIO_Type *lpc11xx_gpio_base[4] = {LPC_GPIO0, LPC_GPIO1, LPC_GPIO2}; + + +void set_gpio_mode(uint16_t pin, uint8_t is_output, uint8_t is_pullup) +{ + uint32_t value; + LPC_GPIO_Type *gpio; + + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<16; /* enable IOCON clock */ + + + if ( is_pullup == 0 ) + value = lpc11xx_pin_info[pin].iocon_gpio_value_no_pullup; + else + value = lpc11xx_pin_info[pin].iocon_gpio_value_pullup; + *(__IO uint32_t *)(((char *)LPC_IOCON)+(size_t)(lpc11xx_pin_info[pin].offset)) = value; + + gpio = lpc11xx_gpio_base[pin >> 5]; + + if ( is_output == 0 ) + gpio->DIR &= ~( 1UL << (pin & 0x01f)); + else + gpio->DIR |= ( 1UL << (pin & 0x01f)); +} + +void set_gpio_level(uint16_t pin, uint8_t level) +{ + + /* assumes that pins are not affected by MASK register */ + LPC_GPIO_Type *gpio = lpc11xx_gpio_base[pin >> 5]; + pin &= 0x01f; + if ( level != 0 ) + { + gpio->SET = 1UL << (pin); + } + else + { + gpio->CLR = 1UL << (pin); + } +} + +uint8_t get_gpio_level(uint16_t pin) +{ + LPC_GPIO_Type *gpio = lpc11xx_gpio_base[pin >> 5]; + pin &= 0x01f; + if ( (gpio->PIN & (1<<(pin))) == 0 ) + return 0; + return 1; +} + + + + +/*========================================================================*/ +/* + SPI + typedef struct { (@ 0x40040000) SSP Structure + union{ + __IO uint32_t CR[2]; (@ 0x40040000) Control Registers. + struct{ + __IO uint32_t CR0; (@ 0x40040000) Control Register 0. Selects the serial clock rate, bus type, and data size. + __IO uint32_t CR1; (@ 0x40040004) Control Register 1. Selects master/slave and other modes. + }; + }; + __IO uint32_t DR; (@ 0x40040008) Data Register. Writes fill the transmit FIFO, and reads empty the receive FIFO. + __I uint32_t SR; (@ 0x4004000C) Status Register + __IO uint32_t CPSR; (@ 0x40040010) Clock Prescale Register + __IO uint32_t IMSC; (@ 0x40040014) Interrupt Mask Set and Clear Register + __I uint32_t RIS; (@ 0x40040018) Raw Interrupt Status Register + __I uint32_t MIS; (@ 0x4004001C) Masked Interrupt Status Register + __IO uint32_t ICR; (@ 0x40040020) SSPICR Interrupt Clear Register + __IO uint32_t DMACR; (@ 0x40040024) DMA Control Register + } LPC_SSP_Type; + + + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<16; enable IOCON clock + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<11; enable SSP clock + LPC_SYSCON->SSPCLKDIV = 1; + + //LPC_IOCON->SCK_LOC = 0; SCK0 at PIO0_10 + LPC_IOCON->PIO0_14 = 2; select SCK at PIO0_14, no pullup + LPC_IOCON->PIO0_17 = 2; select MOSI at PIO0_17, no pullup + + LPC_SSP->CR1 = 0; disable SPI, enable master mode + LPC_SSP->CR0 = 7 | (CPOL << 6) | (CPHA <<7); 8 bit, SPI mode, SCR = 1 (prescale) + LPC_SSP->CPSR = 12; + LPC_SSP->CR1 = 2; enable SPI, (enable master mode) + +*/ + + +/* + setup spi0 + ns is the clock cycle time between 0 and 20000 ns +*/ +void spi_init(uint32_t ns) +{ + uint32_t cpol = 1; + uint32_t cpha = 1; + uint32_t cpsr; + + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<16; /* enable IOCON clock */ + LPC_SYSCON->SYSAHBCLKCTRL |= 1<<11; /* enable SSP0 clock */ + LPC_SYSCON->SSPCLKDIV = 1; + + LPC_SYSCON->PRESETCTRL &= ~(1UL<<0); /* reset SSP0 */ + + LPC_IOCON->PIO0_14 = 2; /* select SCK at PIO0_14 */ + LPC_IOCON->PIO0_17 = 2; /* select MOSI at PIO0_17 */ + + LPC_SYSCON->PRESETCTRL |= 1UL<<0; /* de-asserted reset SSP0 */ + + + LPC_SSP->CR1 = 0; /* disable SPI, enable master mode */ + LPC_SSP->CR0 = 7 | (cpol << 6) | (cpha <<7); /* 8 bit, SPI mode, SCR = 1 (prescale) */ + + /* + calculate CPSR + SystemCoreClock / CPSR = 1000000000 / ns + CPSR = SystemCoreClock * ns / 1000000000 + CPSR = (SystemCoreClock/10000) * ns / 100000 + */ + cpsr = SystemCoreClock; + cpsr /= 10000UL; + cpsr *= ns; + cpsr += 100000UL - 1UL; /* round up */ + cpsr /= 100000UL; + /* ensure that cpsr will be between 2 and 254 */ + if ( cpsr == 0 ) + cpsr = 1; + cpsr++; + cpsr &= 0x0feUL; + LPC_SSP->CPSR = cpsr; + LPC_SSP->CR1 = 2; /* enable SPI, (enable master mode) */ + + /* + for(;;) + spi_out(0x0f5); + */ + /* + set_gpio_mode(PIN(1,0), 1, 0); + for(;;) + { + set_gpio_level(PIN(1,0), 0); + set_gpio_level(PIN(1,0), 0); + set_gpio_level(PIN(1,0), 0); + set_gpio_level(PIN(1,0), 1); + } + */ + +} + +void spi_out(uint8_t data) +{ + while ( (LPC_SSP->SR & 2) == 0 ) + ; + LPC_SSP->DR = data; +} + +/*========================================================================*/ +/* + The following delay procedures must be implemented for u8glib + + void u8g_Delay(uint16_t val) Delay by "val" milliseconds + void u8g_MicroDelay(void) Delay be one microsecond + void u8g_10MicroDelay(void) Delay by 10 microseconds + +*/ + +void u8g_Delay(uint16_t val) +{ + + delay_micro_seconds(1000UL*(uint32_t)val); +} + +void u8g_MicroDelay(void) +{ + delay_micro_seconds(1); +} + +void u8g_10MicroDelay(void) +{ + delay_micro_seconds(10); +} + + + + +/*========================================================================*/ +/* u8glib com procedure */ + +/* gps board */ +/* +uint16_t u8g_pin_a0 = PIN(0,11); +uint16_t u8g_pin_cs = PIN(0,6); +uint16_t u8g_pin_rst = PIN(0,5); +*/ + +/* eval board */ +uint16_t u8g_pin_a0 = PIN(1,1); +uint16_t u8g_pin_cs = PIN(1,2); +uint16_t u8g_pin_rst = PIN(1,0); + + +uint8_t u8g_com_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) +{ + switch(msg) + { + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_INIT: + + if ( arg_val <= U8G_SPI_CLK_CYCLE_50NS ) + { + spi_init(50); + } + else if ( arg_val <= U8G_SPI_CLK_CYCLE_300NS ) + { + spi_init(300); + } + else if ( arg_val <= U8G_SPI_CLK_CYCLE_400NS ) + { + spi_init(400); + } + else + { + spi_init(1200); + } + + set_gpio_mode(u8g_pin_rst, 1, 0); /* output, no pullup */ + set_gpio_mode(u8g_pin_cs, 1, 0); /* output, no pullup */ + set_gpio_mode(u8g_pin_a0, 1, 0); /* output, no pullup */ + + u8g_MicroDelay(); + break; + + case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ + u8g_10MicroDelay(); + set_gpio_level(u8g_pin_a0, arg_val); + u8g_10MicroDelay(); + break; + + case U8G_COM_MSG_CHIP_SELECT: + if ( arg_val == 0 ) + { + /* disable */ + uint8_t i; + /* this delay is required to avoid that the display is switched off too early --> DOGS102 with LPC1114 */ + for( i = 0; i < 5; i++ ) + u8g_10MicroDelay(); + set_gpio_level(u8g_pin_cs, 1); + } + else + { + /* enable */ + set_gpio_level(u8g_pin_cs, 0); + } + u8g_MicroDelay(); + break; + + case U8G_COM_MSG_RESET: + set_gpio_level(u8g_pin_rst, arg_val); + u8g_10MicroDelay(); + break; + + case U8G_COM_MSG_WRITE_BYTE: + spi_out(arg_val); + u8g_MicroDelay(); + break; + + case U8G_COM_MSG_WRITE_SEQ: + case U8G_COM_MSG_WRITE_SEQ_P: + { + register uint8_t *ptr = arg_ptr; + while( arg_val > 0 ) + { + spi_out(*ptr++); + arg_val--; + } + } + break; + } + return 1; +} +