Major changes on the core of the framework from klaute

* Some interferrences with the two timers (usb/led)
* Big cleanup from the codebase and separate logical parts
* Documenting the code
* Big space optimizations on the code to fit on the AVR
This commit is contained in:
Kai Lauterbach 2011-10-19 00:04:59 +02:00 committed by Aaron Mueller
parent ef1aa32741
commit 9ce06c0292
7 changed files with 144 additions and 261 deletions

View file

@ -44,11 +44,9 @@ MCU = attiny2313
# This is only used to define F_CPU in all assembler and c-sources.
F_CPU = 12000000UL
# 8MHz internal (basic firmware)
#LFUSE=0xE4
# external clock
LFUSE=0xFF
HFUSE=0xDF
# external clock, boden, noclkdiv
LFUSE=0xEF
HFUSE=0xDB
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
@ -81,7 +79,7 @@ OPT = s
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
#DEBUG = stabs
DEBUG = # dwarf-2
DEBUG =
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
@ -113,19 +111,17 @@ CINCS = -Iusbdrv
CFLAGS = #-g$(DEBUG)
CFLAGS += $(CDEFS) $(CINCS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
#CFLAGS += -funsigned-char
#CFLAGS += -funsigned-bitfields
#CFLAGS += -fpack-struct
#CFLAGS += -fshort-enums
CFLAGS += -fno-split-wide-types
#CFLAGS += -fno-split-wide-types
CFLAGS += -fno-move-loop-invariants
CFLAGS += -fno-tree-scev-cprop
#CFLAGS += -fno-inline-small-functions
#CFLAGS += -fno-tree-loop-optimize
#CFLAGS += -ffunction-sections
#CFLAGS += -fdata-sections
CFLAGS += -mcall-prologues
CFLAGS += -mtiny-stack
#CFLAGS += -mcall-prologues
#CFLAGS += -mtiny-stack
#CFLAGS += -mint8
CFLAGS += -Wall -Wstrict-prototypes
CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
@ -133,7 +129,7 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
CFLAGS += -DF_CPU=$(F_CPU)
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
#CFLAGS += -fdata-sections
CFLAGS += -Wl,--gc-sections

37
firmware/globals.h Normal file
View file

@ -0,0 +1,37 @@
#define F_CPU 12000000UL
// Bitpopelei
#define set_bit(var, bit) ((var) |= (1 << (bit)))
#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit)))
// Bool
#define FALSE 0
#define TRUE 1
// Definitionen
#define PIXEL_TON 30
#define PIXEL_TOFF 10
#define sleep_nop(cnt) for (uint8_t i = 0; i < cnt; i++) { asm volatile("nop"::); }
// Pixelmakros
#define PSET(x,y,z) (0b01000000 | ((z * 3 + x) + y * 9))
#define PCLEAR(x,y,z) (0b00000000 | ((z * 3 + x) + y * 9))
// Instructions
#define CLEAR 0b10000000
#define SET 0b10010000
#define FPS 0b10110000
#define NEXT 0b11110000
// Variablen
#define VAR_FPS 0
// Für CLEAR und SET
#define CLEAR_ALL 0
#define SET_ALL 0
// Für NEXT
#define JUMP_FORWARD 1
#define JUMP_BACKWARD 2

View file

@ -1,190 +1,91 @@
/*
* Based on the code of the Mini-LED-Cube 1.0
* Based on the code of the Mini-LED-Cube 1.0
*
* Copyright (C) 2009 Paul Wilhelm <paul@mosfetkiller.de>
* http: *mosfetkiller.de/?s=miniledcube
* Copyright (C) 2009 Paul Wilhelm <paul@mosfetkiller.de>
* http: *mosfetkiller.de/?s=miniledcube
*
* Changed by Kai Lauterbach (klaute at web dot de)
*/
#include "main.h"
// Main
// Main
int main(void)
{
// Initialisierung
// Initialisierung
init();
init_usb();
// Hauptschleife
while (1)
// Hauptschleife
//while (1)
for (;;)
{
//wdt_reset(); // we are alive, so don't reset the µC
usbPoll(); // keep connected
/*
unsigned char instruction = pgm_read_byte(&(program_pointer[program_counter]));
if ((instruction & 0b10000000) == 0)
// Pixel
{
unsigned char coord = instruction & 0b00111111; // Uns interessieren nur die 6 untersten Bits
unsigned char y = coord / 9;
unsigned char x = (coord - y * 9) % 3;
unsigned char z = (coord - y * 9) / 3;
buffer[x][y][z] = (instruction & 0b01000000) / 0b01000000;
}
else
// Instruction
{
unsigned char operation = instruction & 0b11110000; // Uns interessieren nur die 4 obersten Bits
if (operation == CLEAR || operation == SET)
{
unsigned char frame = instruction & 0b00001111;
// Folgende Werte entsprechen SET_ALL
unsigned char x_min = 0, x_max = 3, y_min = 0, y_max = 3, z_min = 0, z_max = 3;
// Folgendes kann noch optimiert werden.
// Y-Z-Ebene (links, mitte, rechts)
if (frame == 1) { x_min = 0; x_max = 1; }
if (frame == 2) { x_min = 1; x_max = 2; }
if (frame == 3) { x_min = 2; x_max = 3; }
// X-Z-Ebene (unten, mitte, oben)
if (frame == 4) { y_min = 0; y_max = 1; }
if (frame == 5) { y_min = 1; y_max = 2; }
if (frame == 6) { y_min = 2; y_max = 3; }
// X-Y-Ebene (hinten, mitte, vorne)
if (frame == 7) { z_min = 0; z_max = 1; }
if (frame == 8) { z_min = 1; z_max = 2; }
if (frame == 9) { z_min = 2; z_max = 3; }
if (frame < 10)
{
for (unsigned char z = z_min; z < z_max; z++)
for (unsigned char y = y_min; y < y_max; y++)
for (unsigned char x = x_min; x < x_max; x++)
if (operation == SET) buffer[x][y][z] = 1; else buffer[x][y][z] = 0;
} else
{
for (unsigned char a = 0; a < 3; a++)
for (unsigned char b = 0; b < 3; b++)
{
unsigned char x = 0, y = 0, z = 0;
if (frame == 10) { x = a; y = b; z = b; } // Unten hinten nach oben vorne
if (frame == 11) { x = a; y = a; z = b; } // Unten links nach oben rechts
if (frame == 12) { x = a; y = b; z = 2 - b; } // Unten vorne nach oben hinten
if (frame == 13) { x = a; y = 2 - a; z = b; } // Oben links nach unten rechts
if (frame == 14) { x = b; y = a; z = b; } // Hinten links nach vorne rechts
if (frame == 15) { x = a; y = 2 - b; z = 2 - a; } // Vorne links nach hinten rechts
if (operation == SET) buffer[x][y][z] = 1; else buffer[x][y][z] = 0;
}
}
} else
if (operation == FPS)
{
if (program_counter + 1 < program_length) program_counter++; // else: Fehler
unsigned char byte = pgm_read_byte(&(program_pointer[program_counter]));
fps = byte;
} else
if (operation == NEXT)
{
// VAR_FPS = 0: Frame nicht zeichnen, keine Wartezeit
if (fps > 0)
{
// Temporäres Array ins "echte" Array kopieren
for (unsigned char z = 0; z < 3; z++)
for (unsigned char y = 0; y < 3; y++)
for (unsigned char x = 0; x < 3; x++)
cube[x][y][z] = buffer[x][y][z];
for (unsigned char i = 0; i < fps; i++)
{
_delay_ms(5);
}
}
}
}
// Programmzähler erhöhen, bzw. bei Erreichen des Programmendes wieder von vorn beginnen
if (program_counter + 1 < program_length) program_counter++; else program_counter = 0;
*/
}
}
// Initialisierung
// Initialisierung
void init()
{
// Ports vorbereiten
DDRB = 0b11111111; // PB0-PB7: LED 1-8 (Kathoden)
PORTB = 0b11111111; // HIGH
// Ports vorbereiten
DDRB = 0b11111111; // PB0-PB7: LED 1-8 (Kathoden)
PORTB = 0b11111111; // HIGH
DDRD = 0b1111000; // PD6: LED 9 (Kathode); PD5-PD3: A-C (Anoden)
DDRD = 0b1111000; // PD6: LED 9 (Kathode); PD5-PD3: A-C (Anoden)
PORTD = 0b1000000;
// Timer-Interrupt "TIMER1" vorbereiten
cli();
// Timer-Interrupt "TIMER1" vorbereiten
//cli(); //
set_bit(TIMSK, OCIE1A);
set_bit(TCCR1B, WGM12);
// Animations-Geschwindigkeit
// Animations-Geschwindigkeit
OCR1AH = 0x01;
OCR1AL = 0x00;
clear_bit(TCCR1B, CS12); // Prescaler 64
clear_bit(TCCR1B, CS12); // Prescaler 64
set_bit(TCCR1B, CS11);
set_bit(TCCR1B, CS10);
sei();
}
// Interruptvektor von TIMER1
// Interruptvektor von TIMER1
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
// Pixel multiplexen
/**/
for (unsigned char z = 0; z < 3; z++)
{
for (unsigned char y = 0; y < 3; y++)
{
for (unsigned char x = 0; x < 3; x++)
{
unsigned char n = z * 3 + x;
// LED an
// Pixel multiplexen
for (uint8_t z = 0; z < 3; z++)
{
for (uint8_t y = 0; y < 3; y++)
{
for (uint8_t x = 0; x < 3; x++)
{
uint8_t n = z * 3 + x;
// LED an
if (cube[x][y][z] == 1)
{
if (n < 8) clear_bit(PORTB, n); else clear_bit(PORTD, 6);
set_bit(PORTD, y + 3);
}
// ON-Time
for (unsigned long i = 0; i < PIXEL_TON; i++) { asm volatile("nop"::); }
// ON-Time
sleep_nop(PIXEL_TON);
// LED aus
// LED aus
if (cube[x][y][z] == 1)
{
clear_bit(PORTD, y + 3);
if (n < 8) set_bit(PORTB, n); else set_bit(PORTD, 6);
}
// OFF-Time
for (unsigned long i = 0; i < PIXEL_TOFF; i++) { asm volatile("nop"::); }
// OFF-Time
sleep_nop(PIXEL_TOFF)
}
}
}
/**/
}

View file

@ -4,119 +4,33 @@
// http://mosfetkiller.de/?s=miniledcube
//
// Changed by Kai Lauterbach (klaute at web dot de)
// Interner RC-Oszillator, CKDIV8 Disabled
//
// Externes Quarz, CKDIV8 Disabled
#ifndef __main_h__
#define __main_h__
#define F_CPU 12000000UL
// Includes
#include "globals.h"
// Includes
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
//#include <util/delay.h>
//#include <avr/pgmspace.h>
//#include <avr/wdt.h>
// Bitpopelei
#define set_bit(var, bit) ((var) |= (1 << (bit)))
#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit)))
// Cube-Array
uint8_t cube[3][3][3];
uint8_t buffer[3][3][3]; // Framebuffer
// Bool
#define FALSE 0
#define TRUE 1
volatile uint8_t frame_done = 0;
// Definitionen
#define PIXEL_TON 30
#define PIXEL_TOFF 10
// Cube-Array
unsigned char cube[3][3][3];
unsigned char buffer[3][3][3]; // Framebuffer
// Prototypen
// Prototypen
void init(void);
void loop(uint8_t);
extern void init_usb(void);
extern void usbPoll(void);
/*
// Programmzähler
unsigned int program_counter = 0;
// Framezähler
volatile unsigned char frame_counter = 0, fps = 0;
// Pixelmakros
#define PSET(x,y,z) (0b01000000 | ((z * 3 + x) + y * 9))
#define PCLEAR(x,y,z) (0b00000000 | ((z * 3 + x) + y * 9))
// Instructions
#define CLEAR 0b10000000
#define SET 0b10010000
#define FPS 0b10110000
#define NEXT 0b11110000
// Variablen
#define VAR_FPS 0
// Für CLEAR und SET
#define CLEAR_ALL 0
#define SET_ALL 0
// Für NEXT
#define JUMP_FORWARD 1
#define JUMP_BACKWARD 2
// Animation in pgmspace
const prog_char program_1[] =
{
FPS, 10,
CLEAR, SET + 12, NEXT, CLEAR, SET + 14, NEXT, // Vor- und zurück tanzen
CLEAR, SET + 12, NEXT, CLEAR, SET + 14, NEXT,
CLEAR, SET + 12, NEXT, CLEAR, SET + 15, NEXT,
CLEAR, SET + 12, NEXT, CLEAR, SET + 15,
FPS, 5, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, // Umdrehung
FPS, 5, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
FPS, 6, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT,
FPS, 6, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
FPS, 7, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT,
FPS, 7, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
FPS, 8, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT,
FPS, 8, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
FPS, 9, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT,
FPS, 9, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
FPS, 10, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT,
FPS, 10, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT,
CLEAR, SET + 8, NEXT, CLEAR, SET + 12, NEXT, // Umfallen
CLEAR, SET + 4, NEXT, CLEAR, SET + 5, NEXT, CLEAR, SET + 6, NEXT, // Ebenen
CLEAR, SET + 1, NEXT, CLEAR, SET + 2, NEXT, CLEAR, SET + 3, NEXT,
CLEAR, SET + 7, NEXT, CLEAR, SET + 8, NEXT, CLEAR, SET + 9, NEXT,
FPS, 10, // Außen langlaufen
CLEAR,
PSET(0,0,0), PSET(1,0,0), PSET(0,1,0), PSET(1,1,0), PSET(0,2,0), PSET(1,2,0), NEXT,
PCLEAR(0,0,0), PSET(2,0,0), PCLEAR(0,1,0), PSET(2,1,0), PCLEAR(0,2,0), PSET(2,2,0), NEXT,
PCLEAR(1,0,0), PSET(2,0,1), PCLEAR(1,1,0), PSET(2,1,1), PCLEAR(1,2,0), PSET(2,2,1), NEXT,
PCLEAR(2,0,0), PSET(2,0,2), PCLEAR(2,1,0), PSET(2,1,2), PCLEAR(2,2,0), PSET(2,2,2), NEXT,
PCLEAR(2,0,1), PSET(1,0,2), PCLEAR(2,1,1), PSET(1,1,2), PCLEAR(2,2,1), PSET(1,2,2), NEXT,
PCLEAR(2,0,2), PSET(0,0,2), PCLEAR(2,1,2), PSET(0,1,2), PCLEAR(2,2,2), PSET(0,2,2), NEXT,
PCLEAR(1,0,2), PSET(0,0,1), PCLEAR(1,1,2), PSET(0,1,1), PCLEAR(1,2,2), PSET(0,2,1), NEXT,
PCLEAR(0,0,2), PSET(0,0,0), PCLEAR(0,1,2), PSET(0,1,0), PCLEAR(0,2,2), PSET(0,2,0), NEXT,
PCLEAR(0,0,1), PCLEAR(0,1,1), PCLEAR(0,2,1),
SET + 7, NEXT, CLEAR, SET + 8, NEXT, CLEAR, SET + 9, NEXT,
CLEAR, SET + 8, NEXT, CLEAR, SET + 7, NEXT,
};
const prog_char *program_pointer = program_1;
unsigned int program_length = sizeof(program_1);
*/
#endif // __main_h__

View file

@ -12,19 +12,43 @@
usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
usbRequest_t *rq = (void *)data;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){
if(rq->bRequest == CUSTOM_RQ_SET_STATUS){
if ( (rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR )
{
if ( rq->bRequest == CUSTOM_RQ_SET_STATUS )
{
// receive animation data
/*if (rq->wIndex.bytes[0] == 0)
cube[0][0][0] = 1;
if (rq->wIndex.bytes[0] == 1)
cube[0][0][1] = 1;
if (rq->wIndex.bytes[0] == 2)
cube[0][0][2] = 1;
if (rq->wIndex.bytes[0] == 3)
cube[0][1][0] = 1;*/
if (rq->wIndex.bytes[0] == 0)
x = rq->wValue.bytes[0];
else if (rq->wIndex.bytes[0] == 1)
y = rq->wValue.bytes[0];
else if (rq->wIndex.bytes[0] == 2)
z = rq->wValue.bytes[0];
else if (rq->wIndex.bytes[0] == 3)
cube[x][y][z] = rq->wValue.bytes[0];
} else if ( rq->bRequest == CUSTOM_RQ_GET_STATUS ) {
// Send one byte to the USB host.
}else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){
//static uchar dataBuffer[1]; // buffer must stay valid when usbFunctionSetup returns
//dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0);
//usbMsgPtr = dataBuffer; // tell the driver which data to return
//usbMsgPtr = 0; // tell the driver which data to return
//return 1; // tell the driver to send 1 byte
return 0; // tell the driver to send 1 byte
//return 0; // tell the driver to send 0 byte
}
}else{
/* class requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are
@ -43,11 +67,14 @@ void init_usb(void)
usbInit();
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
i = 0;
while(--i){ /* fake USB disconnect for > 250 ms */
//wdt_reset();
_delay_ms(1);
//sleep_nop(255);
}
usbDeviceConnect();
sei(); // enable global interrupts
@ -68,7 +95,7 @@ void init_usb(void)
...mainloop start...
wdt_reset(); // we are alive, please dont reset the µC
wdt_reset(); // we are alive, please dont reset the µC (optional)
usbPoll(); // keep the usb connection up
...end mainloop...

View file

@ -10,6 +10,8 @@
#ifndef __usb_h__
#define __usb_h__
#include "globals.h"
/*
This example should run on most AVRs with only little changes. No special
hardware resources except INT0 are used. You may have to change usbconfig.h for
@ -19,12 +21,11 @@ We assume that an LED is connected to port B bit 0. If you connect it to a
different port or bit, change the macros below:
*/
#include <avr/io.h>
//#include <avr/wdt.h>
#include <avr/interrupt.h> /* for sei() */
//#include <avr/io.h>
//#include <avr/wdt.h>
#include <util/delay.h> /* for _delay_ms() */
#include <avr/pgmspace.h> /* required by usbdrv.h */
//#include <avr/pgmspace.h> /* required by usbdrv.h */
#include "usbconfig.h"
#include "usbdrv.h"
@ -54,6 +55,13 @@ PROGMEM char usbHidReportDescriptor[22] = { /* USB report descriptor */
void init_usb(void);
volatile uint8_t x;
volatile uint8_t y;
volatile uint8_t z;
// usb buffer
//extern uint8_t buffer[3][3][3]; // Framebuffer
extern uint8_t cube[3][3][3]; // Framebuffer
#endif // __usb_h__

View file

@ -27,11 +27,11 @@ section at the end of this file).
/* This is the port where the USB bus is connected. When you configure it to
* "B", the registers PORTB, PINB and DDRB will be used.
*/
#define USB_CFG_DMINUS_BIT 3
#define USB_CFG_DMINUS_BIT 1
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
* This may be any bit in the port.
*/
#define USB_CFG_DPLUS_BIT 6
#define USB_CFG_DPLUS_BIT 2
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
* This may be any bit in the port. Please note that D+ must also be connected
* to interrupt pin INT0! [You can also use other interrupts, see section
@ -116,7 +116,7 @@ section at the end of this file).
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
* device is powered from the USB bus.
*/
#define USB_CFG_MAX_BUS_POWER 200
#define USB_CFG_MAX_BUS_POWER 250
/* Set this variable to the maximum USB bus power consumption of your device.
* The value is in milliamperes. [It will be divided by two since USB
* communicates power requirements in units of 2 mA.]