diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/bcm2835_intc.h b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/bcm2835_intc.h new file mode 100644 index 00000000..9f87b88e --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/bcm2835_intc.h @@ -0,0 +1,45 @@ +#ifndef _BCM2835_INTC_H_ +#define _BCM2835_INTC_H_ + +//#include "bcm2835.h" + +#define BCM2835_INTC_TOTAL_IRQ 64 + 8 + +#define BCM2835_BASE_INTC (0x2000B200) +#define BCM2835_INTC_IRQ_BASIC (BCM2835_BASE_INTC + 0x00) +#define BCM2835_IRQ_PENDING1 (BCM2835_BASE_INTC + 0x04) +#define BCM2835_IRQ_PENDING2 (BCM2835_BASE_INTC + 0x08) +#define BCM2835_IRQ_FIQ_CTRL (BCM2835_BASE_INTC + 0x0C) +#define BCM2835_IRQ_ENABLE1 (BCM2835_BASE_INTC + 0x10) +#define BCM2835_IRQ_ENABLE2 (BCM2835_BASE_INTC + 0x14) +#define BCM2835_IRQ_ENABLE_BASIC (BCM2835_BASE_INTC + 0x18) +#define BCM2835_IRQ_DISABLE1 (BCM2835_BASE_INTC + 0x1C) +#define BCM2835_IRQ_DISABLE2 (BCM2835_BASE_INTC + 0x20) +#define BCM2835_IRQ_DISABLE_BASIC (BCM2835_BASE_INTC + 0x24) + + + + +#define BCM2835_IRQ_ID_AUX 29 +#define BCM2835_IRQ_ID_SPI_SLAVE 43 +#define BCM2835_IRQ_ID_PWA0 45 +#define BCM2835_IRQ_ID_PWA1 46 +#define BCM2835_IRQ_ID_SMI 48 +#define BCM2835_IRQ_ID_GPIO_0 49 +#define BCM2835_IRQ_ID_GPIO_1 50 +#define BCM2835_IRQ_ID_GPIO_2 51 +#define BCM2835_IRQ_ID_GPIO_3 52 +#define BCM2835_IRQ_ID_I2C 53 +#define BCM2835_IRQ_ID_SPI 54 +#define BCM2835_IRQ_ID_PCM 55 +#define BCM2835_IRQ_ID_UART 57 + + +#define BCM2835_IRQ_ID_TIMER_0 64 +#define BCM2835_IRQ_ID_MAILBOX_0 65 +#define BCM2835_IRQ_ID_DOORBELL_0 66 +#define BCM2835_IRQ_ID_DOORBELL_1 67 +#define BCM2835_IRQ_ID_GPU0_HALTED 68 + + +#endif diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.c b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.c new file mode 100644 index 00000000..485de897 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.c @@ -0,0 +1,134 @@ +/** + * Quick and very Dirty GPIO API. + * + **/ + +#include "gpio.h" + +typedef struct { + unsigned long GPFSEL[6]; ///< Function selection registers. + unsigned long Reserved_1; + unsigned long GPSET[2]; + unsigned long Reserved_2; + unsigned long GPCLR[2]; + unsigned long Reserved_3; + unsigned long GPLEV[2]; + unsigned long Reserved_4; + unsigned long GPEDS[2]; + unsigned long Reserved_5; + unsigned long GPREN[2]; + unsigned long Reserved_6; + unsigned long GPFEN[2]; + unsigned long Reserved_7; + unsigned long GPHEN[2]; + unsigned long Reserved_8; + unsigned long GPLEN[2]; + unsigned long Reserved_9; + unsigned long GPAREN[2]; + unsigned long Reserved_A; + unsigned long GPAFEN[2]; + unsigned long Reserved_B; + unsigned long GPPUD[1]; + unsigned long GPPUDCLK[2]; + //Ignoring the reserved and test bytes +} BCM2835_GPIO_REGS; + +volatile BCM2835_GPIO_REGS * const pRegs = (BCM2835_GPIO_REGS *) (0x20200000); + + +void SetGpioFunction(unsigned int pinNum, unsigned int funcNum) { + + int offset = pinNum / 10; + + unsigned long val = pRegs->GPFSEL[offset]; // Read in the original register value. + + int item = pinNum % 10; + val &= ~(0x7 << (item * 3)); + val |= ((funcNum & 0x7) << (item * 3)); + pRegs->GPFSEL[offset] = val; +} + +void SetGpioDirection(unsigned int pinNum, enum GPIO_DIR dir) { + SetGpioFunction(pinNum,dir); +} + +void SetGpio(unsigned int pinNum, unsigned int pinVal) { + unsigned long offset=pinNum/32; + unsigned long mask=(1<<(pinNum%32)); + + if(pinVal) { + pRegs->GPSET[offset]|=mask; + } else { + pRegs->GPCLR[offset]|=mask; + } +} + +int ReadGpio(unsigned int pinNum) { + return ((pRegs->GPLEV[pinNum/32])>>(pinNum%32))&1; +} + +void EnableGpioDetect(unsigned int pinNum, enum DETECT_TYPE type) +{ + unsigned long mask=(1<GPREN[offset]|=mask; + break; + case DETECT_FALLING: + pRegs->GPFEN[offset]|=mask; + break; + case DETECT_HIGH: + pRegs->GPHEN[offset]|=mask; + break; + case DETECT_LOW: + pRegs->GPLEN[offset]|=mask; + break; + case DETECT_RISING_ASYNC: + pRegs->GPAREN[offset]|=mask; + break; + case DETECT_FALLING_ASYNC: + pRegs->GPAFEN[offset]|=mask; + break; + case DETECT_NONE: + break; + } +} + +void DisableGpioDetect(unsigned int pinNum, enum DETECT_TYPE type) +{ + unsigned long mask=~(1<<(pinNum%32)); + unsigned long offset=pinNum/32; + + switch(type) { + case DETECT_RISING: + pRegs->GPREN[offset]&=mask; + break; + case DETECT_FALLING: + pRegs->GPFEN[offset]&=mask; + break; + case DETECT_HIGH: + pRegs->GPHEN[offset]&=mask; + break; + case DETECT_LOW: + pRegs->GPLEN[offset]&=mask; + break; + case DETECT_RISING_ASYNC: + pRegs->GPAREN[offset]&=mask; + break; + case DETECT_FALLING_ASYNC: + pRegs->GPAFEN[offset]&=mask; + break; + case DETECT_NONE: + break; + } +} + +void ClearGpioInterrupt(unsigned int pinNum) +{ + unsigned long mask=(1<<(pinNum%32)); + unsigned long offset=pinNum/32; + + pRegs->GPEDS[offset]=mask; +} diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.h b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.h new file mode 100644 index 00000000..fa459707 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/gpio.h @@ -0,0 +1,48 @@ +#ifndef _GPIO_H_ +#define _GPIO_H_ + +/* GPIO event detect types */ +enum DETECT_TYPE { + DETECT_NONE, + DETECT_RISING, + DETECT_FALLING, + DETECT_HIGH, + DETECT_LOW, + DETECT_RISING_ASYNC, + DETECT_FALLING_ASYNC +}; + +/* GPIO pull up or down states */ +enum PULL_STATE { + PULL_DISABLE, + PULL_UP, + PULL_DOWN, + PULL_RESERVED +}; + +/* Pin data direction */ +enum GPIO_DIR { + GPIO_IN, + GPIO_OUT +}; + +/* GPIO pin setup */ +void SetGpioFunction (unsigned int pinNum, unsigned int funcNum); +/* A simple wrapper around SetGpioFunction */ +void SetGpioDirection (unsigned int pinNum, enum GPIO_DIR dir); + +/* Set GPIO output level */ +void SetGpio (unsigned int pinNum, unsigned int pinVal); + +/* Read GPIO pin level */ +int ReadGpio (unsigned int pinNum); + +/* GPIO pull up/down resistor control function (NOT YET IMPLEMENTED) */ +int PudGpio (unsigned int pinNum, enum PULL_STATE state); + +/* Interrupt related functions */ +void EnableGpioDetect (unsigned int pinNum, enum DETECT_TYPE type); +void DisableGpioDetect (unsigned int pinNum, enum DETECT_TYPE type); +void ClearGpioInterrupt (unsigned int pinNum); + +#endif diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.c b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.c new file mode 100644 index 00000000..9908b7c4 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.c @@ -0,0 +1,166 @@ +/** + * Integrated Interrupt Controller for RaspberryPi. + * @author James Walmsley + **/ + +#include "interrupts.h" +#include "bcm2835_intc.h" + +static INTERRUPT_VECTOR g_VectorTable[BCM2835_INTC_TOTAL_IRQ]; + + +typedef struct { + unsigned long IRQBasic; // Pending 0 + unsigned long Pending1; + unsigned long Pending2; + unsigned long FIQCtrl; + unsigned long Enable1; + unsigned long Enable2; + unsigned long EnableBasic; + unsigned long Disable1; + unsigned long Disable2; + unsigned long DisableBasic; +} BCM2835_INTC_REGS; + +static volatile BCM2835_INTC_REGS * const pRegs = (BCM2835_INTC_REGS *) (BCM2835_BASE_INTC); + +/** + * Enables all IRQ's in the CPU's CPSR register. + **/ +static void irqEnable() { + __asm volatile("mrs r0,cpsr"); // Read in the cpsr register. + __asm volatile("bic r0,r0,#0x80"); // Clear bit 8, (0x80) -- Causes IRQs to be enabled. + __asm volatile("msr cpsr_c, r0"); // Write it back to the CPSR register +} + +static void irqDisable() { + __asm volatile("mrs r0,cpsr"); // Read in the cpsr register. + __asm volatile("orr r0,r0,#0x80"); // Set bit 8, (0x80) -- Causes IRQs to be disabled. + __asm volatile("msr cpsr_c, r0"); // Write it back to the CPSR register. + +} + +#define clz(a) \ + ({ unsigned long __value, __arg = (a); \ + asm ("clz\t%0, %1": "=r" (__value): "r" (__arg)); \ + __value; }) + +/** + * This is the global IRQ handler on this platform! + * It is based on the assembler code found in the Broadcom datasheet. + * + **/ +void irqHandler() { + register unsigned long ulMaskedStatus; + register unsigned long irqNumber; + + ulMaskedStatus = pRegs->IRQBasic; + + /* Bits 7 through 0 in IRQBasic represent interrupts 64-71 */ + if (ulMaskedStatus & 0xFF) { + irqNumber=64 + 31; + } + + /* Bit 8 in IRQBasic indicates interrupts in Pending1 (interrupts 31-0) */ + else if(ulMaskedStatus & 0x100) { + ulMaskedStatus = pRegs->Pending1; + irqNumber = 0 + 31; + } + + /* Bit 9 in IRQBasic indicates interrupts in Pending2 (interrupts 63-32) */ + else if(ulMaskedStatus & 0x200) { + ulMaskedStatus = pRegs->Pending2; + irqNumber = 32 + 31; + } + + else { + // No interrupt avaialbe, so just return. + return; + } + + /* Keep only least significant bit, in case multiple interrupts have occured */ + ulMaskedStatus&=-ulMaskedStatus; + /* Some magic to determine number of interrupt to serve */ + irqNumber=irqNumber-clz(ulMaskedStatus); + /* Call interrupt handler */ + g_VectorTable[irqNumber].pfnHandler(irqNumber, g_VectorTable[irqNumber].pParam); +} + + +static void stubHandler(int nIRQ, void *pParam) { + /** + * Actually if we get here, we should probably disable the IRQ, + * otherwise we could lock up this system, as there is nothing to + * ackknowledge the interrupt. + **/ +} + +int InitInterruptController() { + int i; + for(i = 0; i < BCM2835_INTC_TOTAL_IRQ; i++) { + g_VectorTable[i].pfnHandler = stubHandler; + g_VectorTable[i].pParam = (void *) 0; + } + return 0; +} + + + +int RegisterInterrupt(int nIRQ, FN_INTERRUPT_HANDLER pfnHandler, void *pParam) { + if(nIRQ<0 || nIRQ>71) + return -1; + + irqDisable(); + { + g_VectorTable[nIRQ].pfnHandler = pfnHandler; + g_VectorTable[nIRQ].pParam = pParam; + } + irqEnable(); + return 0; +} + +int EnableInterrupt(int nIRQ) { + /* Datasheet says "All other bits are unaffected", and I'm counting on that. */ + unsigned int mask=1<<(nIRQ%32); + + if(nIRQ >=0 && nIRQ <=31) { + pRegs->Enable1 = mask; + } else + if(nIRQ >=32 && nIRQ <=63){ + pRegs->Enable2 = mask; + } else + if(nIRQ >= 64 && nIRQ <= 71) { // Basic IRQ enables + pRegs->EnableBasic = mask; + } else + return -1; + + return 0; +} + +int DisableInterrupt(int nIRQ) { + /* Datasheet says "All other bits are unaffected", and I'm counting on that. */ + unsigned int mask=1<<(nIRQ%32); + + if(nIRQ >=0 && nIRQ <=31) { + pRegs->Disable1 = mask; + } else + if(nIRQ >=32 && nIRQ <=63){ + pRegs->Disable2 = mask; + } else + if(nIRQ >= 64 && nIRQ <= 71) { + pRegs->DisableBasic = mask; + } else + return -1; + + return 0; +} + +int EnableInterrupts() { + irqEnable(); + return 0; +} + +int DisableInterrupts() { + irqDisable(); + return 0; +} diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.h b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.h new file mode 100644 index 00000000..d09353a4 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/interrupts.h @@ -0,0 +1,25 @@ +/** + * Tiny Interrupt Manager + * + * @author James Walmsley + * This code is licensed under the GNU GPLv3 license. + **/ + +#ifndef _INTERRUPTS_H_ +#define _INTERRUPTS_H_ + +typedef void (*FN_INTERRUPT_HANDLER)(int nIRQ, void *pParam); + +typedef struct { + FN_INTERRUPT_HANDLER pfnHandler; ///< Function that handles this IRQn + void *pParam; ///< A special parameter that the use can pass to the IRQ. +} INTERRUPT_VECTOR; + +int InitInterruptController (); +int RegisterInterrupt (int nIRQ, FN_INTERRUPT_HANDLER pfnHandler, void *pParam); +int EnableInterrupt (int nIRQ); +int DisableInterrupt (int nIRQ); +int EnableInterrupts (); +int DisableInterrupts (); + +#endif diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/mmio.h b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/mmio.h new file mode 100644 index 00000000..89bea700 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/mmio.h @@ -0,0 +1,24 @@ +/* mmio.h - access to MMIO registers */ + +#ifndef MMIO_H +#define MMIO_H + +#include + +// write to MMIO register +static inline void mmio_write(uint32_t reg, uint32_t data) { + uint32_t *ptr = (uint32_t*)reg; + asm volatile("str %[data], [%[reg]]" + : : [reg]"r"(ptr), [data]"r"(data)); +} + +// read from MMIO register +static inline uint32_t mmio_read(uint32_t reg) { + uint32_t *ptr = (uint32_t*)reg; + uint32_t data; + asm volatile("ldr %[data], [%[reg]]" + : [data]"=r"(data) : [reg]"r"(ptr)); + return data; +} + +#endif // #ifndef MMIO_H diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.c b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.c new file mode 100644 index 00000000..92f837e7 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.c @@ -0,0 +1,125 @@ +/* uart.c - UART initialization & communication */ +/* Reference material: + * http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + * Chapter 13: UART + */ + +#include +#include +#include + +enum { + // The GPIO registers base address. + GPIO_BASE = 0x20200000, + + // The offsets for reach register. + + // Controls actuation of pull up/down to ALL GPIO pins. + GPPUD = (GPIO_BASE + 0x94), + + // Controls actuation of pull up/down for specific GPIO pin. + GPPUDCLK0 = (GPIO_BASE + 0x98), + + // The base address for UART. + UART0_BASE = 0x20201000, + + // The offsets for reach register for the UART. + UART0_DR = (UART0_BASE + 0x00), + UART0_RSRECR = (UART0_BASE + 0x04), + UART0_FR = (UART0_BASE + 0x18), + UART0_ILPR = (UART0_BASE + 0x20), + UART0_IBRD = (UART0_BASE + 0x24), + UART0_FBRD = (UART0_BASE + 0x28), + UART0_LCRH = (UART0_BASE + 0x2C), + UART0_CR = (UART0_BASE + 0x30), + UART0_IFLS = (UART0_BASE + 0x34), + UART0_IMSC = (UART0_BASE + 0x38), + UART0_RIS = (UART0_BASE + 0x3C), + UART0_MIS = (UART0_BASE + 0x40), + UART0_ICR = (UART0_BASE + 0x44), + UART0_DMACR = (UART0_BASE + 0x48), + UART0_ITCR = (UART0_BASE + 0x80), + UART0_ITIP = (UART0_BASE + 0x84), + UART0_ITOP = (UART0_BASE + 0x88), + UART0_TDR = (UART0_BASE + 0x8C), +}; + +/* + * delay function + * int32_t delay: number of cycles to delay + * + * This just loops times in a way that the compiler + * wont optimize away. + */ +static void delay(int32_t count) { + asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" + : : [count]"r"(count) : "cc"); +} + +/* + * Initialize UART0. + */ +void uart_init() { + // Disable UART0. + mmio_write(UART0_CR, 0x00000000); + // Setup the GPIO pin 14 && 15. + + // Disable pull up/down for all GPIO pins & delay for 150 cycles. + mmio_write(GPPUD, 0x00000000); + delay(150); + + // Disable pull up/down for pin 14,15 & delay for 150 cycles. + mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + + // Write 0 to GPPUDCLK0 to make it take effect. + mmio_write(GPPUDCLK0, 0x00000000); + + // Clear pending interrupts. + mmio_write(UART0_ICR, 0x7FF); + + // Set integer & fractional part of baud rate. + // Divider = UART_CLOCK/(16 * Baud) + // Fraction part register = (Fractional part * 64) + 0.5 + // UART_CLOCK = 3000000; Baud = 115200. + + // Divider = 3000000/(16 * 115200) = 1.627 = ~1. + // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. + mmio_write(UART0_IBRD, 1); + mmio_write(UART0_FBRD, 40); + + // Enable FIFO & 8 bit data transmissio (1 stop bit, no parity). + mmio_write(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); + + // Mask all interrupts. + mmio_write(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | + (1 << 6) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10)); + + // Enable UART0, receive & transfer part of UART. + mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); +} + +/* + * Transmit a byte via UART0. + * uint8_t Byte: byte to send. + */ +void uart_putc(uint8_t byte) { + // wait for UART to become ready to transmit + while (1) { + if (!(mmio_read(UART0_FR) & (1 << 5))) { + break; + } + } + mmio_write(UART0_DR, byte); +} + +/* + * print a string to the UART one character at a time + * const char *str: 0-terminated string + */ +void uart_puts(const char *str) { + while (*str) { + uart_putc(*str++); + } +} diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.h b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.h new file mode 100644 index 00000000..fe7f64aa --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Drivers/uart.h @@ -0,0 +1,25 @@ +/* uart.h - UART initialization & communication */ + +#ifndef UART_H +#define UART_H + +#include + +/* + * Initialize UART0. + */ +void uart_init(); + +/* + * Transmit a byte via UART0. + * uint8_t Byte: byte to send. + */ +void uart_putc(uint8_t byte); + +/* + * print a string to the UART one character at a time + * const char *str: 0-terminated string + */ +void uart_puts(const char *str); + +#endif // #ifndef UART_H diff --git a/boards/base/RaspberryPi/example-FreeRTOS/FreeRTOSConfig.h b/boards/base/RaspberryPi/example-FreeRTOS/FreeRTOSConfig.h new file mode 100644 index 00000000..c2477416 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/FreeRTOSConfig.h @@ -0,0 +1,139 @@ +/* + FreeRTOS V8.0.0 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configTICK_RATE_HZ ( ( portTickType ) 1000 ) +#define configCPU_CLOCK_HZ ( ( unsigned long ) 24000000 ) +#define configPERIPHERAL_CLOCK_HZ ( 40000000UL ) +#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) +#define configISR_STACK_SIZE ( 250 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 4096 ) ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 3 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 + + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_eTaskGetState 1 + + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 +(lowest) to 0 (1?) (highest). */ +#define configKERNEL_INTERRUPT_PRIORITY 255 +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */ + + +/* This is the value being used as per the ST library which permits 16 +priority values, 0 to 15. This must correspond to the +configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest +NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/boards/base/RaspberryPi/example-FreeRTOS/Makefile b/boards/base/RaspberryPi/example-FreeRTOS/Makefile new file mode 100644 index 00000000..c1751204 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/Makefile @@ -0,0 +1,73 @@ +# build environment +PREFIX ?= /your compiler path/gcc-arm-none-eabi-4_8-2014q1 +ARCH ?= $(PREFIX)/bin/arm-none-eabi + +CC = ${ARCH}-gcc +CPP = ${ARCH}-g++ +AS = ${ARCH}-as +LD = ${ARCH}-ld +AR = ${ARCH}-ar +OBJCOPY = ${ARCH}-objcopy + +PLATFORM = raspi +LINKER_SCRIPT = raspberrypi.ld + +CFLAGS = -march=armv6z -g -Wall -Wextra +ASFLAGS = -g + +CFLAGS_FOR_TARGET = #-mcpu=arm1176jzf-s +ASFLAGS_FOR_TARGET = #-mcpu=arm1176jzf-s +LDFLAGS = #--error-unresolved-symbols + +GFXLIB := ../uGFX +include $(GFXLIB)/gfx.mk +include $(GFXLIB)/drivers/gdisp/framebuffer/driver.mk + +OSLIB := ../FreeRTOS +MODULES := $(OSLIB)/Source/portable/GCC/RaspberryPi +MODULES += $(OSLIB)/Source/portable/MemMang +MODULES += $(OSLIB)/Source +MODULES += Drivers + +SRC_DIR := $(MODULES) +INC_DIR := $(addsuffix /include,$(SRC_DIR)) +BUILD_DIR := $(addsuffix /build,$(SRC_DIR)) + +INCLUDEDIRS := $(OSLIB)/Source/portable/GCC/RaspberryPi +INCLUDEDIRS += $(OSLIB)/Source/include +INCLUDEDIRS += Drivers +INCLUDEDIRS += $(GFXINC) + +INCLUDES := $(addprefix -I,$(INCLUDEDIRS)) + +ASRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.s)) +AOBJ := $(ASRC:.s=.o) +CSRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) +CSRC += $(GFXSRC) +COBJ := $(CSRC:.c=.o) + +vpath %.c $(SRC_DIR) +vpath %.cpp $(SRC_DIR) +vpath %.s $(SRC_DIR) + +%.o: %.c + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) $(CFLAGS) -c -o $*.o $< + +%.o: %.s + $(AS) $(ASFLAGS_FOR_TARGET) $(INCLUDES) $(ASFLAGS) -o $*.o $< + +OBJ = $(AOBJ) $(COBJ) + +bin/kernel.img: bin/kernel.elf + ${OBJCOPY} -O binary $< $@ + +bin/kernel.elf: LDFLAGS += -L "$(PREFIX)/lib/gcc/arm-none-eabi/4.8.3" -lgcc +bin/kernel.elf: LDFLAGS += -L "$(PREFIX)/arm-none-eabi/lib" -lc +bin/kernel.elf: $(OBJ) + ${LD} $(OBJ) -Map bin/kernel.map -o $@ -T $(LINKER_SCRIPT) ${LDFLAGS} + +clean: + rm -f bin/*.elf bin/*.img bin/*.map $(OBJ) + + + diff --git a/boards/base/RaspberryPi/example-FreeRTOS/main.c b/boards/base/RaspberryPi/example-FreeRTOS/main.c new file mode 100644 index 00000000..3a64a7bb --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/main.c @@ -0,0 +1,82 @@ +#include +#include + +#include "Drivers/interrupts.h" + +#include "gfx.h" + +static void displayTask(void *pvParameters) { + coord_t width, height; + // Get the screen size + width = gdispGetWidth(); + height = gdispGetHeight(); + + // Code Here + gdispDrawBox(10, 10, width/2, height/2, Yellow); + gdispFillArea(width/2, height/2, width/2-10, height/2-10, Blue); + gdispDrawLine(5, 30, width-50, height-40, Red); + + while(1) + { + vTaskDelay(1000); + } + + return; +} + +/** + * This is the systems main entry, some call it a boot thread. + * + * -- Absolutely nothing wrong with this being called main(), just it doesn't have + * -- the same prototype as you'd see in a linux program. + **/ +int main(void) { + + DisableInterrupts(); + InitInterruptController(); + + // Initialize and clear the display + gfxInit(); + + xTaskCreate(displayTask, + (portCHAR *)"Display Task", + 128, + NULL, + 0, + NULL); + + vTaskStartScheduler(); + + /* + * We should never get here, but just in case something goes wrong, + * we'll place the CPU into a safe loop. + */ + while(1) { + ; + } + + return 0; +} + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time task stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is + called if a task stack overflow is detected. Note the system/interrupt + stack is not checked. */ + taskDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vApplicationTickHook( void ) +{ + /* This function will be called by each tick interrupt if + configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be + added here, but the tick hook is called from an interrupt context, so + code must not attempt to block, and only the interrupt safe FreeRTOS API + functions can be used (those that end in FromISR()). */ +} diff --git a/boards/base/RaspberryPi/example-FreeRTOS/raspberrypi.ld b/boards/base/RaspberryPi/example-FreeRTOS/raspberrypi.ld new file mode 100644 index 00000000..ece588b5 --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/raspberrypi.ld @@ -0,0 +1,70 @@ +/** + * BlueThunder Linker Script for the raspberry Pi! + * + * + * + **/ +MEMORY +{ + RESERVED (r) : ORIGIN = 0x00000000, LENGTH = 32K + INIT_RAM (rwx) : ORIGIN = 0x00008000, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x00010000, LENGTH = 128M +} + +ENTRY(_start) + +SECTIONS { + /* + * Our init section allows us to place the bootstrap code at address 0x8000 + * + * This is where the Graphics processor forces the ARM to start execution. + * However the interrupt vector code remains at 0x0000, and so we must copy the correct + * branch instructions to 0x0000 - 0x001C in order to get the processor to handle interrupts. + * + */ + .init : { + KEEP(*(.init)) + } > INIT_RAM = 0 + + .module_entries : { + __module_entries_start = .; + KEEP(*(.module_entries)) + KEEP(*(.module_entries.*)) + __module_entries_end = .; + __module_entries_size = SIZEOF(.module_entries); + } > INIT_RAM + + + /** + * This is the main code section, it is essentially of unlimited size. (128Mb). + * + **/ + .text : { + *(.text) + } > RAM + + /* + * Next we put the data. + */ + .data : { + *(.data) + } > RAM + + .bss : + { + __bss_start = .; + *(.bss) + *(.bss.*) + __bss_end = .; + } > RAM + + /** + * Place HEAP here??? + **/ + + /** + * Stack starts at the top of the RAM, and moves down! + **/ + _estack = ORIGIN(RAM) + LENGTH(RAM); +} + diff --git a/boards/base/RaspberryPi/example-FreeRTOS/startup.s b/boards/base/RaspberryPi/example-FreeRTOS/startup.s new file mode 100644 index 00000000..286f396c --- /dev/null +++ b/boards/base/RaspberryPi/example-FreeRTOS/startup.s @@ -0,0 +1,102 @@ +.extern system_init +.extern __bss_start +.extern __bss_end +.extern vFreeRTOS_ISR +.extern vPortYieldProcessor +.extern DisableInterrupts +.extern main + .section .init + .globl _start +;; +_start: + ;@ All the following instruction should be read as: + ;@ Load the address at symbol into the program counter. + + ldr pc,reset_handler ;@ Processor Reset handler -- we will have to force this on the raspi! + ;@ Because this is the first instruction executed, of cause it causes an immediate branch into reset! + + ldr pc,undefined_handler ;@ Undefined instruction handler -- processors that don't have thumb can emulate thumb! + ldr pc,swi_handler ;@ Software interrupt / TRAP (SVC) -- system SVC handler for switching to kernel mode. + ldr pc,prefetch_handler ;@ Prefetch/abort handler. + ldr pc,data_handler ;@ Data abort handler/ + ldr pc,unused_handler ;@ -- Historical from 26-bit addressing ARMs -- was invalid address handler. + ldr pc,irq_handler ;@ IRQ handler + ldr pc,fiq_handler ;@ Fast interrupt handler. + + ;@ Here we create an exception address table! This means that reset/hang/irq can be absolute addresses +reset_handler: .word reset +undefined_handler: .word undefined_instruction +swi_handler: .word vPortYieldProcessor +prefetch_handler: .word prefetch_abort +data_handler: .word data_abort +unused_handler: .word unused +irq_handler: .word vFreeRTOS_ISR +fiq_handler: .word fiq + +reset: + ;@ In the reset handler, we need to copy our interrupt vector table to 0x0000, its currently at 0x8000 + + mov r0,#0x8000 ;@ Store the source pointer + mov r1,#0x0000 ;@ Store the destination pointer. + + ;@ Here we copy the branching instructions + ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9} ;@ Load multiple values from indexed address. ; Auto-increment R0 + stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9} ;@ Store multiple values from the indexed address. ; Auto-increment R1 + + ;@ So the branches get the correct address we also need to copy our vector table! + ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9} ;@ Load from 4*n of regs (8) as R0 is now incremented. + stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9} ;@ Store this extra set of data. + + + ;@ Set up the various STACK pointers for different CPU modes + ;@ (PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD2 + msr cpsr_c,r0 + mov sp,#0x8000 + + ;@ (PSR_FIQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD1 + msr cpsr_c,r0 + mov sp,#0x4000 + + ;@ (PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD3 + msr cpsr_c,r0 + mov sp,#0x8000000 + + ldr r0, =__bss_start + ldr r1, =__bss_end + + mov r2, #0 + +zero_loop: + cmp r0,r1 + it lt + strlt r2,[r0], #4 + blt zero_loop + + bl DisableInterrupts + + + ;@ mov sp,#0x1000000 + b main ;@ We're ready?? Lets start main execution! + .section .text + +undefined_instruction: + b undefined_instruction + +prefetch_abort: + b prefetch_abort + +data_abort: + b data_abort + +unused: + b unused + +fiq: + b fiq + +hang: + b hang + diff --git a/drivers/gdisp/PCD8544/PCD8544.h b/drivers/gdisp/PCD8544/PCD8544.h new file mode 100644 index 00000000..3716a4a8 --- /dev/null +++ b/drivers/gdisp/PCD8544/PCD8544.h @@ -0,0 +1,45 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _PCD8544_H +#define _PCD8544_H + +#define PCD8544_SET_FUNC 0x20 // Function set +#define PCD8544_H 0x01 +#define PCD8544_V 0x02 +#define PCD8544_PD 0x04 + +#define PCD8544_SET_DISPLAY 0x08 +#define PCD8544_DISPLAY_MODE_BLANK 0x00 // bit D = 0, E = 0 +#define PCD8544_DISPLAY_MODE_FILL 0x01 // bit D = 0, E = 1 +#define PCD8544_DISPLAY_MODE_NORMAL 0x04 // bit D = 1, E = 0 +#define PCD8544_DISPLAY_MODE_INVERT 0x05 // bit D = 1, E = 1 + +#define PCD8544_SET_Y 0x40 // 0 0 1 0 0 Y3 Y2 Y1 Y0 +#define PCD8544_SET_X 0x80 // 0 1 X6 X5 X4 X3 X2 X1 X0 + +// ========================================= + +#define PCD8544_SET_TEMP 0x04 // set temperature coefficient (TCx) +#define PCD8544_TEMP_MODE_0 0x00 // TC1 = 0, TC0 = 0 +#define PCD8544_TEMP_MODE_1 0x01 // TC1 = 0, TC0 = 1 +#define PCD8544_TEMP_MODE_2 0x02 // TC1 = 1, TC0 = 0 +#define PCD8544_TEMP_MODE_3 0x03 // TC1 = 1, TC0 = 1 + +#define PCD8544_SET_BIAS 0x10 // set bias system (BSx) +#define PCD8544_BIAS_MODE_7 0x00 // 1 to 100 +#define PCD8544_BIAS_MODE_6 0x01 // 1 to 80 +#define PCD8544_BIAS_MODE_5 0x02 // 1 to 65 +#define PCD8544_BIAS_MODE_4 0x03 // 1 to 48 +#define PCD8544_BIAS_MODE_3 0x04 // 1 to 40 or 1 to 34 +#define PCD8544_BIAS_MODE_2 0x05 // 1 to 24 +#define PCD8544_BIAS_MODE_1 0x06 // 1 to 18 or 1 to 16 +#define PCD8544_BIAS_MODE_0 0x07 // 1 to 10 or 1 to 9 or 1 to 8 + +#define PCD8544_SET_VOP 0x80 // write VOP to register, 1 VOP6 VOP5 VOP4 VOP3 VOP2 VOP1 VOP0 + +#endif /* _PCD8544_H */ diff --git a/drivers/gdisp/PCD8544/board_PCD8544_template.h b/drivers/gdisp/PCD8544/board_PCD8544_template.h new file mode 100644 index 00000000..08ec130d --- /dev/null +++ b/drivers/gdisp/PCD8544/board_PCD8544_template.h @@ -0,0 +1,43 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static inline void init_board(GDisplay *g) { + (void) g; +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + (void) g; + (void) cmd; +} + +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/PCD8544/driver.mk b/drivers/gdisp/PCD8544/driver.mk new file mode 100644 index 00000000..262550d3 --- /dev/null +++ b/drivers/gdisp/PCD8544/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/PCD8544 +GFXSRC += $(GFXLIB)/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c diff --git a/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c b/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c new file mode 100644 index 00000000..377f3d8b --- /dev/null +++ b/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c @@ -0,0 +1,233 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_PCD8544 +#include "drivers/gdisp/PCD8544/gdisp_lld_config.h" +#include "src/gdisp/driver.h" +#include "board_PCD8544.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define GDISP_SCREEN_HEIGHT 48 +#define GDISP_SCREEN_WIDTH 84 + +#define GDISP_INITIAL_CONTRAST 51 +#define GDISP_INITIAL_BACKLIGHT 100 + +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0) + +#include "drivers/gdisp/PCD8544/PCD8544.h" + +/*===========================================================================*/ +/* Driver local routines. */ +/*===========================================================================*/ + +// Some common routines and macros +#define RAM(g) ((uint8_t *)g->priv) + +#define xyaddr(x, y) ((x) + ((y) >> 3) * GDISP_SCREEN_WIDTH) +#define xybit(y) (1 << ((y) & 7)) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/* + * As this controller can't update on a pixel boundary we need to maintain the + * the entire display surface in memory so that we can do the necessary bit + * operations. Fortunately it is a small display in monochrome. + * Display 48 * 84 / 8 = 504 + */ + +#define GDISP_SCREEN_BYTES ((GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT) / 8) + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + if (!(g->priv = gfxAlloc(GDISP_SCREEN_BYTES))) + gfxHalt("GDISP PCD8544: Failed to allocate private memory"); + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(100); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(100); + + acquire_bus(g); + + write_cmd(g, PCD8544_SET_FUNC | PCD8544_H); + write_cmd(g, PCD8544_SET_TEMP | PCD8544_TEMP_MODE_2); + write_cmd(g, PCD8544_SET_BIAS | PCD8544_BIAS_MODE_4); + write_cmd(g, PCD8544_SET_VOP | (0x40)); + write_cmd(g, PCD8544_SET_FUNC); + write_cmd(g, PCD8544_SET_DISPLAY | PCD8544_DISPLAY_MODE_NORMAL); + write_cmd(g, PCD8544_SET_X); // X = 0 + write_cmd(g, PCD8544_SET_Y); // Y = 0 + + coord_t i; + + for (i = 0; i < GDISP_SCREEN_BYTES; i++) { + write_data(g, 0x00, 1); + } + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + + return TRUE; +} + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + + // Don't flush if we don't need it. + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) { + return; + } + + acquire_bus(g); + + write_cmd(g, PCD8544_SET_X | 0); // X = 0 + write_cmd(g, PCD8544_SET_Y | 0); // Y = 0 + + coord_t i; + + for (i = 0; i < GDISP_SCREEN_BYTES; i++) { + write_data(g, RAM(g)[i], 1); + } + + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = g->g.Width - g->p.x - 1; + break; + case GDISP_ROTATE_180: + x = g->g.Width - g->p.x - 1; + y = g->g.Height - g->p.y - 1; + break; + case GDISP_ROTATE_270: + x = g->g.Height - g->p.y - 1; + y = g->p.x; + break; + } + #else + x = g->p.x; + y = g->p.y; + #endif + + if (gdispColor2Native(g->p.color) != Black) { + RAM(g)[xyaddr(x, y)] |= xybit(y); + } else { + RAM(g)[xyaddr(x, y)] &= ~xybit(y); + } + + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_NEED_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + write_cmd(g, PCD8544_SET_FUNC | PCD8544_PD); + break; + case powerOn: + write_cmd(g, PCD8544_SET_FUNC); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + write_cmd(g, PCD8544_SET_VOP | (unsigned)g->p.ptr); + g->g.Contrast = (unsigned)g->p.ptr; + return; + } + } +#endif + +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/PCD8544/gdisp_lld_config.h b/drivers/gdisp/PCD8544/gdisp_lld_config.h new file mode 100644 index 00000000..6ad8a571 --- /dev/null +++ b/drivers/gdisp/PCD8544/gdisp_lld_config.h @@ -0,0 +1,28 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +// Set this to your frame buffer pixel format. +#ifndef GDISP_LLD_PIXELFORMAT + #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO +#endif + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ diff --git a/drivers/gdisp/PCF8812/PCF8812.h b/drivers/gdisp/PCF8812/PCF8812.h new file mode 100644 index 00000000..c2695b71 --- /dev/null +++ b/drivers/gdisp/PCF8812/PCF8812.h @@ -0,0 +1,53 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _PCF8812_H +#define _PCF8812_H + +#define PCF8812_SET_FUNC 0x20 // Function set +#define PCF8812_H 0x01 +#define PCF8812_V 0x02 +#define PCF8812_PD 0x04 + +#define PCF8812_SET_DISPLAY 0x08 +#define PCF8812_DISPLAY_MODE_BLANK 0x00 // bit D = 0, E = 0 +#define PCF8812_DISPLAY_MODE_FILL 0x01 // bit D = 0, E = 1 +#define PCF8812_DISPLAY_MODE_NORMAL 0x04 // bit D = 1, E = 0 +#define PCF8812_DISPLAY_MODE_INVERT 0x05 // bit D = 1, E = 1 + +#define PCF8812_SET_PRS 0x10 // Set Vop range, VLCD programming range select + +#define PCF8812_SET_Y 0x40 // 0 0 1 0 0 Y3 Y2 Y1 Y0 +#define PCF8812_SET_X 0x80 // 0 1 X6 X5 X4 X3 X2 X1 X0 + +// ========================================= + +#define PCF8812_SET_TEMP 0x04 // set temperature coefficient (TCx) +#define PCF8812_TEMP_MODE_0 0x00 // TC1 = 0, TC0 = 0 +#define PCF8812_TEMP_MODE_1 0x01 // TC1 = 0, TC0 = 1 +#define PCF8812_TEMP_MODE_2 0x02 // TC1 = 1, TC0 = 0 +#define PCF8812_TEMP_MODE_3 0x03 // TC1 = 1, TC0 = 1 + +#define PCF8812_SET_VMULT 0x08 // Set voltage multiplier factor +#define PCF8812_VMULT_MODE_0 0x00 // S1 = 0, S0 = 0 - 2 × voltage multiplier +#define PCF8812_VMULT_MODE_1 0x01 // S1 = 0, S0 = 1 - 3 × voltage multiplier +#define PCF8812_VMULT_MODE_2 0x02 // S1 = 1, S0 = 0 - 4 × voltage multiplier +#define PCF8812_VMULT_MODE_3 0x03 // S1 = 1, S0 = 1 - 5 × voltage multiplier + +#define PCF8812_SET_BIAS 0x10 // set bias system (BSx) +#define PCF8812_BIAS_MODE_7 0x00 // 1 to 100 +#define PCF8812_BIAS_MODE_6 0x01 // 1 to 80 +#define PCF8812_BIAS_MODE_5 0x02 // 1 to 65 +#define PCF8812_BIAS_MODE_4 0x03 // 1 to 48 +#define PCF8812_BIAS_MODE_3 0x04 // 1 to 40 or 1 to 34 +#define PCF8812_BIAS_MODE_2 0x05 // 1 to 24 +#define PCF8812_BIAS_MODE_1 0x06 // 1 to 18 or 1 to 16 +#define PCF8812_BIAS_MODE_0 0x07 // 1 to 10 or 1 to 9 or 1 to 8 + +#define PCF8812_SET_VOP 0x80 // write VOP to register, 1 VOP6 VOP5 VOP4 VOP3 VOP2 VOP1 VOP0 + +#endif /* _PCF8812_H */ diff --git a/drivers/gdisp/PCF8812/README.md b/drivers/gdisp/PCF8812/README.md new file mode 100644 index 00000000..b8b9a84a --- /dev/null +++ b/drivers/gdisp/PCF8812/README.md @@ -0,0 +1,5 @@ +Driver for PCF8812/OM6206 controller +========================== +Displays based on this controller: + Nokia 3410 + Siemens C55/A55/A52 \ No newline at end of file diff --git a/drivers/gdisp/PCF8812/board_PCF8812_template.h b/drivers/gdisp/PCF8812/board_PCF8812_template.h new file mode 100644 index 00000000..08ec130d --- /dev/null +++ b/drivers/gdisp/PCF8812/board_PCF8812_template.h @@ -0,0 +1,43 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static inline void init_board(GDisplay *g) { + (void) g; +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + (void) g; + (void) cmd; +} + +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c b/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c new file mode 100644 index 00000000..27ce5b91 --- /dev/null +++ b/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c @@ -0,0 +1,237 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_PCF8812 +#include "drivers/gdisp/PCF8812/gdisp_lld_config.h" +#include "src/gdisp/driver.h" +#include "board_PCF8812.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define GDISP_MATRIX_HEIGHT 72 +#define GDISP_MATRIX_WIDTH 102 + +#define GDISP_SCREEN_HEIGHT 65 +#define GDISP_SCREEN_WIDTH 96 + +#define GDISP_INITIAL_CONTRAST 51 +#define GDISP_INITIAL_BACKLIGHT 100 + +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0) + +#include "drivers/gdisp/PCF8812/PCF8812.h" + +/*===========================================================================*/ +/* Driver local routines. */ +/*===========================================================================*/ + +// Some common routines and macros +#define RAM(g) ((uint8_t *)g->priv) + +#define xyaddr(x, y) ((x) + ((y) >> 3) * GDISP_MATRIX_WIDTH) +#define xybit(y) (1 << ((y) & 7)) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/* + * As this controller can't update on a pixel boundary we need to maintain the + * the entire display surface in memory so that we can do the necessary bit + * operations. Fortunately it is a small display in monochrome. + * Matrix 102 * 65 / 8 = 828,75 bytes. + * Display 96 * 65 / 8 = 780 + */ + +//#define GDISP_SCREEN_BYTES ((GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT) / 8) +#define GDISP_MATRIX_BYTES ((GDISP_MATRIX_WIDTH * GDISP_MATRIX_HEIGHT) / 8) // real height 65 pixels, this fix 65 / 8 != 9 + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + if (!(g->priv = gfxAlloc(GDISP_MATRIX_BYTES))) + gfxHalt("GDISP PCF8812: Failed to allocate private memory"); + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(100); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(100); + + acquire_bus(g); + + write_cmd(g, PCF8812_SET_FUNC | PCF8812_H); + write_cmd(g, PCF8812_SET_TEMP | PCF8812_TEMP_MODE_2); + write_cmd(g, PCF8812_SET_BIAS | PCF8812_BIAS_MODE_4); + write_cmd(g, PCF8812_SET_VOP | (0x40)); + write_cmd(g, PCF8812_SET_FUNC); + write_cmd(g, PCF8812_SET_DISPLAY | PCF8812_DISPLAY_MODE_NORMAL); + write_cmd(g, PCF8812_SET_X); // X = 0 + write_cmd(g, PCF8812_SET_Y); // Y = 0 + + coord_t i; + + for (i = 0; i < GDISP_MATRIX_BYTES; i++) { + write_data(g, 0x00, 1); + } + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + + return TRUE; +} + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + + // Don't flush if we don't need it. + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) { + return; + } + + acquire_bus(g); + + write_cmd(g, PCF8812_SET_X | 0); // X = 0 + write_cmd(g, PCF8812_SET_Y | 0); // Y = 0 + + coord_t i; + + for (i = 0; i < GDISP_MATRIX_BYTES; i++) { + write_data(g, RAM(g)[i], 1); + } + + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = g->g.Width - g->p.x - 1; + break; + case GDISP_ROTATE_180: + x = g->g.Width - g->p.x - 1; + y = g->g.Height - g->p.y - 1; + break; + case GDISP_ROTATE_270: + x = g->g.Height - g->p.y - 1; + y = g->p.x; + break; + } + #else + x = g->p.x; + y = g->p.y; + #endif + + if (gdispColor2Native(g->p.color) != Black) { + RAM(g)[xyaddr(x, y)] |= xybit(y); + } else { + RAM(g)[xyaddr(x, y)] &= ~xybit(y); + } + + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_NEED_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + write_cmd(g, PCF8812_SET_FUNC | PCF8812_PD); + break; + case powerOn: + write_cmd(g, PCF8812_SET_FUNC); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + g->g.Contrast = (unsigned)g->p.ptr; + return; + } + } +#endif + +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/PCF8812/gdisp_lld_config.h b/drivers/gdisp/PCF8812/gdisp_lld_config.h new file mode 100644 index 00000000..6ad8a571 --- /dev/null +++ b/drivers/gdisp/PCF8812/gdisp_lld_config.h @@ -0,0 +1,28 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +// Set this to your frame buffer pixel format. +#ifndef GDISP_LLD_PIXELFORMAT + #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO +#endif + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */