diff --git a/feedback/firmware/Makefile b/feedback/firmware/Makefile new file mode 100644 index 0000000..7225ebd --- /dev/null +++ b/feedback/firmware/Makefile @@ -0,0 +1,115 @@ +PRG = feedback +AVRCANLIB_PATH = ../../avr-can-lib +OBJ = main.o \ + $(AVRCANLIB_PATH)/src/at90can_buffer.o \ + $(AVRCANLIB_PATH)/src/at90can.o \ + $(AVRCANLIB_PATH)/src/at90can_disable_dyn_filter.o \ + $(AVRCANLIB_PATH)/src/at90can_error_register.o \ + $(AVRCANLIB_PATH)/src/at90can_get_buf_message.o \ + $(AVRCANLIB_PATH)/src/at90can_get_dyn_filter.o \ + $(AVRCANLIB_PATH)/src/at90can_get_message.o \ + $(AVRCANLIB_PATH)/src/at90can_send_buf_message.o \ + $(AVRCANLIB_PATH)/src/at90can_send_message.o \ + $(AVRCANLIB_PATH)/src/at90can_set_dyn_filter.o \ + $(AVRCANLIB_PATH)/src/at90can_set_mode.o \ + $(AVRCANLIB_PATH)/src/can_buffer.o +# These were defined for the avr-can-lib, but they really, really +# shouldn't be used there because they affect the whole program. +OPTIMIZE = -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +PROGRAMMER = usbtiny + +MCU_TARGET = atmega32m1 +DEFS = -DF_CPU=16000000UL -DHAS_CAN_CONFIG_H + +INCLUDES = -I. -I$(AVRCANLIB_PATH) +LIBS = + +LFUSE = 0xdf +HFUSE = 0xd9 +EFUSE = 0xfe + +EXTRA_CLEAN_FILES = + +# You should not have to change anything below here. + +CC = avr-gcc +DUDE = avrdude + +HOST_CC = gcc +HOST_CFLAGS = -O0 -g +HOST_LDFLAGS = + +# Override is only needed by avr-lib build system. + +override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) $(INCLUDES) +override LDFLAGS = -Wl,-Map,$(PRG).map + +DUDEFLAGS = -c $(PROGRAMMER) -p $(MCU_TARGET) + +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump + +all: $(PRG).elf lst text eeprom + +$(PRG).elf: $(OBJ) $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + rm -f $(OBJ) $(PRG).elf $(PRG).lst $(PRG).map $(PRG).bin $(PRG).hex $(PRG).srec $(PRG)_eeprom.bin $(PRG)_eeprom.hex $(PRG)_eeprom.srec $(EXTRA_CLEAN_FILES) + +lst: $(PRG).lst + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +# Rules for flashing, EEPROM writing and fuse bit setting + +flash: $(PRG).hex $(PRG)_eeprom.hex + $(DUDE) $(DUDEFLAGS) -U eeprom:w:$(PRG)_eeprom.hex:i -U flash:w:$(PRG).hex:i + +flashprg: $(PRG).hex + $(DUDE) $(DUDEFLAGS) -U flash:w:$(PRG).hex:i + +flasheep: $(PRG)_eeprom.hex + $(DUDE) $(DUDEFLAGS) -U eeprom:w:$(PRG)_eeprom.hex:i + +fuse: + $(DUDE) $(DUDEFLAGS) -U hfuse:w:$(HFUSE):m -U lfuse:w:$(LFUSE):m -U efuse:w:$(EFUSE):m + +# Rules for building the .text rom images + +text: hex bin srec + +hex: $(PRG).hex +bin: $(PRG).bin +srec: $(PRG).srec + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.srec: %.elf + $(OBJCOPY) -j .text -j .data -O srec $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -O binary $< $@ + +# Rules for building the .eeprom rom images + +eeprom: ehex ebin esrec + +ehex: $(PRG)_eeprom.hex +ebin: $(PRG)_eeprom.bin +esrec: $(PRG)_eeprom.srec + +%_eeprom.hex: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \ + || { echo empty $@ not generated; exit 0; } + +%_eeprom.srec: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \ + || { echo empty $@ not generated; exit 0; } + +%_eeprom.bin: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \ + || { echo empty $@ not generated; exit 0; } + diff --git a/feedback/firmware/can_config.h b/feedback/firmware/can_config.h new file mode 100644 index 0000000..547b9db --- /dev/null +++ b/feedback/firmware/can_config.h @@ -0,0 +1,79 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define CAN_CONFIG_LOADED + +// ----------------------------------------------------------------------------- +/* Global settings for building the can-lib and application program. + * + * The following two #defines must be set identically for the can-lib and + * your application program. They control the underlying CAN struct. If the + * settings disagree, the underlying CAN struct will be broken, with + * unpredictable results. + * If can.h detects that any of the #defines is not defined, it will set them + * to the default values shown here, so it is in your own interest to have a + * consistent setting. Ommiting the #defines in both can-lib and application + * program will apply the defaults in a consistent way too. + * + * Select if you want to use 29 bit identifiers. + */ +#define SUPPORT_EXTENDED_CANID 1 + +/* Select if you want to use timestamps. + * Timestamps are sourced from a register internal to the AT90CAN. + * Selecting them on any other controller will have no effect, they will + * be 0 all the time. + */ +#define SUPPORT_TIMESTAMPS 0 + + +// ----------------------------------------------------------------------------- +/* Global settings for building the can-lib. + * + * Select ONE CAN controller for which you are building the can-lib. + */ +#define SUPPORT_MCP2515 0 +#define SUPPORT_AT90CAN 1 +#define SUPPORT_SJA1000 0 + + +// ----------------------------------------------------------------------------- +/* Setting for MCP2515 + * + * Declare which pins you are using for communication. + * Remember NOT to use them in your application! + * It is a good idea to use bits from the port that carries MOSI, MISO, SCK. + */ +#define MCP2515_CS B,4 +#define MCP2515_INT B,2 + +// ----------------------------------------------------------------------------- +// Setting for SJA1000 + +#define SJA1000_INT E,0 +#define SJA1000_MEMORY_MAPPED 1 + +// memory-mapped interface +#define SJA1000_BASE_ADDR 0x8000 // for ATMega162 + +/* +// port-interface +#define SJA1000_WR D,6 +#define SJA1000_RD D,7 + +#define SJA1000_ALE E,1 +#define SJA1000_CS C,0 +#define SJA1000_DATA A +*/ + +// ----------------------------------------------------------------------------- +// Setting for AT90CAN + +// Number of CAN messages which are buffered in RAM additinally to the MObs +#define CAN_RX_BUFFER_SIZE 16 +#define CAN_TX_BUFFER_SIZE 8 + +// only available if CAN_TX_BUFFER_SIZE > 0 +#define CAN_FORCE_TX_ORDER 1 + +#endif // CONFIG_H diff --git a/feedback/firmware/main.c b/feedback/firmware/main.c new file mode 100644 index 0000000..f741c9d --- /dev/null +++ b/feedback/firmware/main.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +static void init() { + // Set PB as input, pull-up off + DDRB = 0; + // Set PC0/4/6 as input, pull-up off + DDRC &= ~(_BV(DDC0) | _BV(DDC4) | _BV(DDC6)); + + // Initialize CAN interface + can_init(BITRATE_125_KBPS); + // Regular receive/transmit mode + can_set_mode(NORMAL_MODE); + + // Filter for status requests + can_filter_t filter = { + .id = 0x10, + .mask = 0x7ff, + .flags = { + .rtr = 1, + .extended = 0, + }, + }; + can_set_filter(0, &filter); + + // Enable interrupts to start reception + sei(); +} + +static void send_status() { + // Get GPIO state + // PB -> invert -> Dend..Hend, Dempty..Fempty + uint8_t statusl = ~PINB; + // PC0,6,4 -> invert -> Gempty, Hempty, Reset + uint8_t pinc = ~PINC; + uint8_t gempty = (pinc & _BV(0)) ? _BV(0) : 0; + uint8_t hempty = (pinc & _BV(6)) ? _BV(1) : 0; + uint8_t swres = (pinc & _BV(4)) ? _BV(2) : 0; + uint8_t statush = gempty | hempty | swres; + + if (can_check_free_buffer()) { + can_t msg = { + .id = 0x10, + .flags = { + .rtr = 0, + }, + .length = 2, + .data = { statush, statusl, }, + }; + can_send_message(&msg); + } +} + +static void loop() { + // Check for new messages + if (can_check_message()) { + can_t msg = { 0 }; + uint8_t status = can_get_message(&msg); + if (status != 0) { + switch (msg.id) { + case 0x10: + if (msg.flags.rtr) { + send_status(); + } + } + } + } +} + +int main() { + init(); + while (1) { + loop(); + } +} +