Add sys/avr/lib
This commit is contained in:
parent
981f54213b
commit
746daf1306
|
@ -1,159 +0,0 @@
|
|||
#include <u8g2.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
u8g2_t u8g2;
|
||||
|
||||
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
|
||||
uint8_t *data;
|
||||
|
||||
switch(msg) {
|
||||
case U8X8_MSG_BYTE_INIT:
|
||||
// CLOCK (SCLK)
|
||||
DDRB |= (1 << 1);
|
||||
// DATA (MOSI)
|
||||
DDRB |= (1 << 2);
|
||||
// SPI2X: Double SPI Speed bit
|
||||
SPSR |= (1 << SPI2X);
|
||||
// Enable / Master
|
||||
SPCR = ((1 << SPE) | (1 << MSTR));
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_SET_DC:
|
||||
u8x8_gpio_SetDC(u8x8, arg_int);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_START_TRANSFER:
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
|
||||
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_SEND:
|
||||
data = (uint8_t *)arg_ptr;
|
||||
while( arg_int > 0 ) {
|
||||
SPDR = (uint8_t)*data;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
data++;
|
||||
arg_int--;
|
||||
}
|
||||
break;
|
||||
case U8X8_MSG_BYTE_END_TRANSFER:
|
||||
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
|
||||
{
|
||||
switch(msg){
|
||||
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
|
||||
DDRB |= (1<<0); // CS
|
||||
DDRB |= (1<<4); // DC
|
||||
DDRA |= (1<<7); // RESET
|
||||
break; // can be used to setup pins
|
||||
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
|
||||
// At 16Mhz, 1 instruction = 62.5ns, no action here.
|
||||
break;
|
||||
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
|
||||
// At 16Mhz, 1 instruction = 62.5ns, no action here.
|
||||
break;
|
||||
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
|
||||
for(int i=0 ; i < arg_int ; i++)
|
||||
_delay_us(10);
|
||||
break;
|
||||
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
|
||||
for(int i=0 ; i < arg_int ; i++)
|
||||
_delay_ms(1);
|
||||
break;
|
||||
// case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
|
||||
// break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
|
||||
// case U8X8_MSG_GPIO_D0: // D0 or SPI clock pin: Output level in arg_int
|
||||
// case U8X8_MSG_GPIO_SPI_CLOCK:
|
||||
// if(arg_int)
|
||||
// PORTB |= (1<<1);
|
||||
// else
|
||||
// PORTB &= ~(1<<1);
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D1: // D1 or SPI data pin: Output level in arg_int
|
||||
// //case U8X8_MSG_GPIO_SPI_DATA:
|
||||
// if(arg_int)
|
||||
// PORTB |= (1<<2);
|
||||
// else
|
||||
// PORTB &= ~(1<<2);
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int
|
||||
// break;
|
||||
case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTB |= (1<<0);
|
||||
else
|
||||
PORTB &= ~(1<<0);
|
||||
break;
|
||||
case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTB |= (1<<4);
|
||||
else
|
||||
PORTB &= ~(1<<4);
|
||||
break;
|
||||
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTA |= (1<<7);
|
||||
else
|
||||
PORTA &= ~(1<<7);
|
||||
break;
|
||||
// case U8X8_MSG_GPIO_CS1: // CS1 (chip select) pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_CS2: // CS2 (chip select) pin: Output level in arg_int
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
|
||||
// break; // arg_int=1: Input dir with pullup high for I2C clock pin
|
||||
// case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
|
||||
// break; // arg_int=1: Input dir with pullup high for I2C data pin
|
||||
// case U8X8_MSG_GPIO_MENU_SELECT:
|
||||
// u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_MENU_NEXT:
|
||||
// u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_MENU_PREV:
|
||||
// u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
|
||||
// break;
|
||||
// case U8X8_MSG_GPIO_MENU_HOME:
|
||||
// u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
|
||||
// break;
|
||||
default:
|
||||
u8x8_SetGPIOResult(u8x8, 1); // default return value
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
u8g2_Setup_sh1106_128x64_vcomh0_f(
|
||||
&u8g2, U8G2_R0,
|
||||
u8x8_byte_4wire_hw_spi, u8x8_gpio_and_delay
|
||||
);
|
||||
u8g2_InitDisplay(&u8g2);
|
||||
u8g2_SetPowerSave(&u8g2, 0);
|
||||
while(1){
|
||||
for(uint8_t i=0;i<(128-20);i++){
|
||||
u8g2_ClearBuffer(&u8g2);
|
||||
u8g2_DrawBox(&u8g2, i,0,20,64);
|
||||
u8g2_SendBuffer(&u8g2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#include <u8g2.h>
|
||||
#include <util/delay.h>
|
||||
#include <u8x8_avr.h>
|
||||
|
||||
#define P_CPU_NS (1000000000UL / F_CPU)
|
||||
|
||||
u8g2_t u8g2;
|
||||
|
||||
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
|
||||
{
|
||||
// Re-use library for delays
|
||||
if(u8x8_avr_delay(u8x8, msg, arg_int, arg_ptr))
|
||||
return 1;
|
||||
|
||||
switch(msg){
|
||||
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
|
||||
DDRB |= (1<<0); // CS
|
||||
DDRB |= (1<<4); // DC
|
||||
DDRA |= (1<<7); // RESET
|
||||
break; // can be used to setup pins
|
||||
case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTB |= (1<<0);
|
||||
else
|
||||
PORTB &= ~(1<<0);
|
||||
break;
|
||||
case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTB |= (1<<4);
|
||||
else
|
||||
PORTB &= ~(1<<4);
|
||||
break;
|
||||
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
|
||||
if(arg_int)
|
||||
PORTA |= (1<<7);
|
||||
else
|
||||
PORTA &= ~(1<<7);
|
||||
break;
|
||||
default:
|
||||
u8x8_SetGPIOResult(u8x8, 1); // default return value
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
u8g2_Setup_sh1106_128x64_vcomh0_f(
|
||||
&u8g2, U8G2_R0,
|
||||
u8x8_byte_avr_hw_spi,
|
||||
u8x8_gpio_and_delay
|
||||
);
|
||||
u8g2_InitDisplay(&u8g2);
|
||||
u8g2_SetPowerSave(&u8g2, 0);
|
||||
while(1){
|
||||
u8g2_ClearBuffer(&u8g2);
|
||||
u8g2_SetFont(&u8g2, u8g2_font_ncenB14_tr);
|
||||
u8g2_DrawStr(&u8g2, 0, 15, "Hello!");
|
||||
u8g2_SendBuffer(&u8g2);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ SIZE = avr-size
|
|||
MCU = at90usb1286
|
||||
F_CPU = 16000000
|
||||
U8G2_SRC = ../../../csrc
|
||||
AVR_LIB_SRC = ../lib
|
||||
CFLAGS = \
|
||||
-mmcu=$(MCU) \
|
||||
-DF_CPU=$(F_CPU)UL \
|
||||
|
@ -12,12 +13,13 @@ CFLAGS = \
|
|||
-Werror \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-I$(U8G2_SRC)/
|
||||
-I$(U8G2_SRC)/ \
|
||||
-I$(AVR_LIB_SRC)
|
||||
LDFLAGS = \
|
||||
-Wl,--gc-sections \
|
||||
-mmcu=$(MCU)
|
||||
|
||||
SRC = $(shell ls $(U8G2_SRC)/*.c) main.c
|
||||
SRC = $(shell ls $(U8G2_SRC)/*.c) $(shell ls $(AVR_LIB_SRC)/*.c) main.c
|
||||
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#include "u8x8_avr.h"
|
||||
#include <util/delay.h>
|
||||
|
||||
#define P_CPU_NS (1000000000UL / F_CPU)
|
||||
|
||||
uint8_t u8x8_byte_avr_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
|
||||
uint8_t *data;
|
||||
|
||||
switch(msg) {
|
||||
case U8X8_MSG_BYTE_INIT:
|
||||
DDRB |= (1 << 1); // CLOCK (SCLK)
|
||||
DDRB |= (1 << 2); // DATA (MOSI)
|
||||
SPSR |= (1 << SPI2X); // SPI2X: Double SPI Speed bit
|
||||
SPCR = ((1 << SPE) | (1 << MSTR)); // Enable / Master
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_SET_DC:
|
||||
u8x8_gpio_SetDC(u8x8, arg_int);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_START_TRANSFER:
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
|
||||
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
|
||||
break;
|
||||
case U8X8_MSG_BYTE_SEND:
|
||||
data = (uint8_t *)arg_ptr;
|
||||
while( arg_int > 0 ) {
|
||||
SPDR = (uint8_t)*data;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
data++;
|
||||
arg_int--;
|
||||
}
|
||||
break;
|
||||
case U8X8_MSG_BYTE_END_TRANSFER:
|
||||
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
|
||||
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t u8x8_avr_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
|
||||
{
|
||||
uint8_t cycles;
|
||||
|
||||
switch(msg){
|
||||
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
|
||||
// At 20Mhz, each cycle is 50ns, the call itself is slower.
|
||||
break;
|
||||
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
|
||||
// Approximate best case values...
|
||||
#define CALL_CYCLES 26UL
|
||||
#define CALC_CYCLES 4UL
|
||||
#define RETURN_CYCLES 4UL
|
||||
#define CYCLES_PER_LOOP 4UL
|
||||
|
||||
cycles = (100UL * arg_int) / (P_CPU_NS * CYCLES_PER_LOOP);
|
||||
|
||||
if(cycles > CALL_CYCLES + RETURN_CYCLES + CALC_CYCLES) break;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (cycles) : "0" (cycles) // 2 cycles
|
||||
);
|
||||
break;
|
||||
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
|
||||
for(int i=0 ; i < arg_int ; i++)
|
||||
_delay_us(10);
|
||||
break;
|
||||
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
|
||||
for(int i=0 ; i < arg_int ; i++)
|
||||
_delay_ms(1);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#include <u8g2.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t u8x8_byte_avr_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8x8_avr_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
Loading…
Reference in New Issue