Tectu/ugfx слито с master

ugfx_release_2.6
pashamray 2014-07-10 08:04:52 +03:00
commit b46e58ba6c
23 changed files with 1775 additions and 0 deletions

View File

@ -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

View File

@ -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<<pinNum);
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 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;
}

View File

@ -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

View File

@ -0,0 +1,166 @@
/**
* Integrated Interrupt Controller for RaspberryPi.
* @author James Walmsley <james@fullfat-fs.co.uk>
**/
#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;
}

View File

@ -0,0 +1,25 @@
/**
* Tiny Interrupt Manager
*
* @author James Walmsley <james@fullfat-fs.co.uk>
* 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

View File

@ -0,0 +1,24 @@
/* mmio.h - access to MMIO registers */
#ifndef MMIO_H
#define MMIO_H
#include <stdint.h>
// 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

View File

@ -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 <stdint.h>
#include <mmio.h>
#include <uart.h>
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 <delay> 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++);
}
}

View File

@ -0,0 +1,25 @@
/* uart.h - UART initialization & communication */
#ifndef UART_H
#define UART_H
#include <stdint.h>
/*
* 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

View File

@ -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 */

View File

@ -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)

View File

@ -0,0 +1,82 @@
#include <FreeRTOS.h>
#include <task.h>
#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()). */
}

View File

@ -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);
}

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -0,0 +1,2 @@
GFXINC += $(GFXLIB)/drivers/gdisp/PCD8544
GFXSRC += $(GFXLIB)/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -0,0 +1,5 @@
Driver for PCF8812/OM6206 controller
==========================
Displays based on this controller:
Nokia 3410
Siemens C55/A55/A52

View File

@ -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 */

View File

@ -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

View File

@ -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 */