diff --git a/sys/avr/at90usb1286/main.c b/sys/avr/at90usb1286/main.c deleted file mode 100644 index a1a53c8f..00000000 --- a/sys/avr/at90usb1286/main.c +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include - -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); - } - } -} \ No newline at end of file diff --git a/sys/avr/hello/main.c b/sys/avr/hello/main.c new file mode 100644 index 00000000..66324ab3 --- /dev/null +++ b/sys/avr/hello/main.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#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); + } +} \ No newline at end of file diff --git a/sys/avr/at90usb1286/makefile b/sys/avr/hello/makefile similarity index 81% rename from sys/avr/at90usb1286/makefile rename to sys/avr/hello/makefile index 166b6836..cc352443 100644 --- a/sys/avr/at90usb1286/makefile +++ b/sys/avr/hello/makefile @@ -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) diff --git a/sys/avr/lib/u8x8_avr.c b/sys/avr/lib/u8x8_avr.c new file mode 100644 index 00000000..fb2e4b96 --- /dev/null +++ b/sys/avr/lib/u8x8_avr.c @@ -0,0 +1,79 @@ +#include "u8x8_avr.h" +#include + +#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; +} diff --git a/sys/avr/lib/u8x8_avr.h b/sys/avr/lib/u8x8_avr.h new file mode 100644 index 00000000..69497d85 --- /dev/null +++ b/sys/avr/lib/u8x8_avr.h @@ -0,0 +1,5 @@ +#include +#include + +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); \ No newline at end of file