Skip to content

Commit

Permalink
Add firmware example + some formating cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcornil-git committed Dec 13, 2024
1 parent 769b193 commit 69e0f7f
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 43 deletions.
65 changes: 65 additions & 0 deletions examples/board_sh1106/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
SH1106 OLED demo (navigation menu for a motor controller)
=========================================================
See detailed description of the emulated system here https://github.com/jpcornil-git/Cone2Hank

- Use arrows to navigate menu
- <enter> to select
- <space> to start,pause or stop (long press) motor
- 'v' to start/stop VCD traces
- 'q' or ESC to quit

NOTE: Emulation may be slightly slower than realtime and a keypress has to be long enough to cope with that.

Usage
=====
Command line options:

$ sh1106demo.elf --help
Usage: sh1106demo.elf [...] <firmware>
[--help|-h|-?] Display this usage message and exit
[--list-cores] List all supported AVR cores and exit
[-v] Raise verbosity level
(can be passed more than once)
[--freq|-f <freq>] Sets the frequency for an .hex firmware
[--mcu|-m <device>] Sets the MCU type for an .hex firmware
[--gdb|-g [<port>]] Listen for gdb connection on <port> (default 1234)
[--output|-o <file>] VCD file to save signal traces (default gtkwave_trace.vcd)
[--start-vcd|-s Start VCD output from reset
[--pc-trace|-p Add PC to VCD traces
[--add-trace|-at <name=[portpin|irq|trace]@addr/mask or [sram8|sram16]@addr>]
Add signal to be included in VCD output
<firmware> An ELF file (can include debugging syms)

Examples
========
Execute firmware.elf (with no .mmcu section -> -m and -f required) on system

$ sh1106demo.elf -m atmega32u4 -f 16000000 firmware_no_mmcu.elf

Start system and wait for gdb to connect, load firmware, ...

$ sh1106demo.elf -m atmega32u4 -f 16000000 -g

Execute firmware.elf on system and trace signals in a VCD file

1. .mmcu section of the firmware includes something like:

#include "avr_mcu_section.h"

extern void *__brkval;

AVR_MCU (F_CPU, "atmega32u4" );
AVR_MCU_VOLTAGES(3300, 3300, 3300);
AVR_MCU_VCD_FILE("simavr.vcd", 10000000);

const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = {
{ AVR_MCU_VCD_SYMBOL("Encoder"), .what = (void*) &PIND, .mask=(1<<PIND2), },
{ AVR_MCU_VCD_SRAM_16("Heap"), .what = (void*)(&__brkval), },
};

2. Options from the command line:
- Add a 16 bits trace for Stack Pointer (SPL/SPH) (could also be in the section above)
- Add a (16 bits) trace for Program Counter (PC)
- Start VCD dump (set to "simavr.vcd" in the .mmcu section) from reset

$ sh1106demo.elf --add-trace Stack=sram16@0x5d -p -s firmware_mmcu.elf
Binary file added examples/board_sh1106/firmware_no_mmcu.elf
Binary file not shown.
86 changes: 43 additions & 43 deletions examples/parts/sh1106_virt.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ sh1106_update_command_register (sh1106_t *part)
return;
case SH1106_VIRT_DISP_NORMAL:
sh1106_set_flag (part, SH1106_FLAG_DISPLAY_INVERTED,
0);
0);
sh1106_set_flag (part, SH1106_FLAG_DIRTY, 1);
//printf ("SH1106: DISPLAY NORMAL\n");
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_DISP_INVERTED:
sh1106_set_flag (part, SH1106_FLAG_DISPLAY_INVERTED,
1);
1);
sh1106_set_flag (part, SH1106_FLAG_DIRTY, 1);
//printf ("SH1106: DISPLAY INVERTED\n");
SH1106_CLEAR_COMMAND_REG(part);
Expand All @@ -86,48 +86,48 @@ sh1106_update_command_register (sh1106_t *part)
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_PAGE_START_ADDR
... SH1106_VIRT_SET_PAGE_START_ADDR
+ SH1106_VIRT_PAGES - 1:
... SH1106_VIRT_SET_PAGE_START_ADDR
+ SH1106_VIRT_PAGES - 1:
part->cursor.page = part->spi_data
- SH1106_VIRT_SET_PAGE_START_ADDR;
- SH1106_VIRT_SET_PAGE_START_ADDR;
//printf ("SH1106: SET PAGE ADDRESS: 0x%02x\n", part->cursor.page);
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_COLUMN_LOW_NIBBLE
... SH1106_VIRT_SET_COLUMN_LOW_NIBBLE + 0xF:
... SH1106_VIRT_SET_COLUMN_LOW_NIBBLE + 0xF:
part->spi_data -= SH1106_VIRT_SET_COLUMN_LOW_NIBBLE;
part->cursor.column = (part->cursor.column & 0xF0) | (part->spi_data & 0xF);
//printf ("SH1106: SET COLUMN LOW NIBBLE: 0x%02x\n",part->spi_data);
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_COLUMN_HIGH_NIBBLE
... SH1106_VIRT_SET_COLUMN_HIGH_NIBBLE + 0xF:
... SH1106_VIRT_SET_COLUMN_HIGH_NIBBLE + 0xF:
part->spi_data -= SH1106_VIRT_SET_COLUMN_HIGH_NIBBLE;
part->cursor.column = (part->cursor.column & 0xF) | ((part->spi_data & 0xF) << 4);
//printf ("SH1106: SET COLUMN HIGH NIBBLE: 0x%02x\n", part->spi_data);
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_SEG_REMAP_0:
sh1106_set_flag (part, SH1106_FLAG_SEGMENT_REMAP_0,
1);
1);
//printf ("SH1106: SET COLUMN ADDRESS 0 TO OLED SEG0 to \n");
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_SEG_REMAP_131:
sh1106_set_flag (part, SH1106_FLAG_SEGMENT_REMAP_0,
0);
0);
//printf ("SH1106: SET COLUMN ADDRESS 131 TO OLED SEG0 to \n");
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_COM_SCAN_NORMAL:
sh1106_set_flag (part, SH1106_FLAG_COM_SCAN_NORMAL,
1);
1);
//printf ("SH1106: SET COM OUTPUT SCAN DIRECTION NORMAL \n");
SH1106_CLEAR_COMMAND_REG(part);
return;
case SH1106_VIRT_SET_COM_SCAN_INVERTED:
sh1106_set_flag (part, SH1106_FLAG_COM_SCAN_NORMAL,
0);
0);
//printf ("SH1106: SET COM OUTPUT SCAN DIRECTION REMAPPED \n");
SH1106_CLEAR_COMMAND_REG(part);
return;
Expand Down Expand Up @@ -356,51 +356,51 @@ void
sh1106_connect (sh1106_t * part, sh1106_wiring_t * wiring)
{
avr_connect_irq (
avr_io_getirq (part->avr, AVR_IOCTL_SPI_GETIRQ(0),
SPI_IRQ_OUTPUT),
part->irq + IRQ_SH1106_SPI_BYTE_IN);
avr_io_getirq (part->avr, AVR_IOCTL_SPI_GETIRQ(0),
SPI_IRQ_OUTPUT),
part->irq + IRQ_SH1106_SPI_BYTE_IN);

avr_connect_irq (
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->chip_select.port),
wiring->chip_select.pin),
part->irq + IRQ_SH1106_ENABLE);
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->chip_select.port),
wiring->chip_select.pin),
part->irq + IRQ_SH1106_ENABLE);

avr_connect_irq (
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->data_instruction.port),
wiring->data_instruction.pin),
part->irq + IRQ_SH1106_DATA_INSTRUCTION);
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->data_instruction.port),
wiring->data_instruction.pin),
part->irq + IRQ_SH1106_DATA_INSTRUCTION);

avr_connect_irq (
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->reset.port),
wiring->reset.pin),
part->irq + IRQ_SH1106_RESET);
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->reset.port),
wiring->reset.pin),
part->irq + IRQ_SH1106_RESET);
}

void
sh1106_connect_twi (sh1106_t * part, sh1106_wiring_t * wiring)
{
avr_connect_irq (
avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_OUTPUT),
part->irq + IRQ_SH1106_TWI_OUT);
avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_OUTPUT),
part->irq + IRQ_SH1106_TWI_OUT);

avr_connect_irq (
part->irq + IRQ_SH1106_TWI_IN,
avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_INPUT));
part->irq + IRQ_SH1106_TWI_IN,
avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_INPUT));

if (wiring)
{
avr_connect_irq (
avr_io_getirq (part->avr,
AVR_IOCTL_IOPORT_GETIRQ(
wiring->reset.port),
wiring->reset.pin),
part->irq + IRQ_SH1106_RESET);
AVR_IOCTL_IOPORT_GETIRQ(
wiring->reset.port),
wiring->reset.pin),
part->irq + IRQ_SH1106_RESET);
}
}

Expand All @@ -418,21 +418,21 @@ sh1106_init (struct avr_t *avr, struct sh1106_t * part, int width, int height)
part->write_cursor_end.page = SH1106_VIRT_PAGES-1;
part->write_cursor_end.column = SH1106_VIRT_COLUMNS-1;

AVR_LOG(avr, LOG_OUTPUT, "SH1106: size %dx%d (flags=0x%04x)\n", part->columns, part->rows, part->flags);
AVR_LOG(avr, LOG_OUTPUT, "SH1106: size %dx%d (flags=0x%04x)\n", part->columns, part->rows, part->flags);
/*
* Register callbacks on all our IRQs
*/
part->irq = avr_alloc_irq (&avr->irq_pool, 0, IRQ_SH1106_COUNT,
irq_names);

avr_irq_register_notify (part->irq + IRQ_SH1106_SPI_BYTE_IN,
sh1106_spi_in_hook, part);
sh1106_spi_in_hook, part);
avr_irq_register_notify (part->irq + IRQ_SH1106_RESET,
sh1106_reset_hook, part);
sh1106_reset_hook, part);
avr_irq_register_notify (part->irq + IRQ_SH1106_ENABLE,
sh1106_cs_hook, part);
sh1106_cs_hook, part);
avr_irq_register_notify (part->irq + IRQ_SH1106_DATA_INSTRUCTION,
sh1106_di_hook, part);
sh1106_di_hook, part);
avr_irq_register_notify (part->irq + IRQ_SH1106_TWI_OUT,
sh1106_twi_hook, part);
sh1106_twi_hook, part);
}

0 comments on commit 69e0f7f

Please sign in to comment.