Moved libraries to lib directory, added hardware abstraction lib

This commit is contained in:
bigalex 2012-09-02 23:17:59 +02:00
parent 9810b13d17
commit 8dc4c5bbc7
8 changed files with 589 additions and 34 deletions

View File

@ -4,12 +4,13 @@
#curl http://seb.exse.net/ledtest.hex > ledtest.hex && avrflash.sh m168 -F -v -v -U flash:w:ledtest.hex
#MCU = atmega88p
#MCU = atmega328p
#MCU = atmega644
F_CPU = 8000000
MCU = atmega88p
#F_CPU = 20000000
F_CPU = 8000000
QUARZ = 8MHZ
#internal RC/8
@ -35,7 +36,7 @@ OPT = s
##########################################################################################################
# List C source files here. (C dependencies are automatically generated.)
SRC = main.c lib/synth.c lib/usart.c
SRC = main.c lib/synth.c lib/usart.c lib/bughal.c
##########################################################################################################

39
firmware/lib/bughal.c Normal file
View File

@ -0,0 +1,39 @@
#include <inttypes.h>
#include "bughal.h"
/* Hardware abstraction layer for Pentabug hardware */
/*
* initialize LEDs on C0-C3
*/
void init_leds(void){
//enable LED channels as output
DDRC |= (1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
// both LEDs off
PORTC &= ~(1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
//TCCR2A = (1 << WGM21);
//TCCR2B = (1 << CS20)|(1 << CS21);
//OCR2A = 255; /* TOP */
// TCNT2 = 0;
// /*enable interrupt*/
// TIMSK2 |= (1<<OCIE2A);
return;
};
void init_buzzr(int mode);
void init_switch();
static void init_motor(void)
{
/* vibration motor on B1, initially off: */
DDRB |= (1 << PORTB1);
PORTB &= ~( 1<<PORTB1);
return;
}

17
firmware/lib/bughal.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef BUGHAL_H
#define BUGHAL_H
/* Hardware abstraction layer for Pentabug hardware */
enum { BUZZR_OUT, //initialize buzzer for OUTPUT mode (emmiting soundwaves)
BUZZR_IN //initialize buzzer for INPUT mode (registering soundwaves)
};
void init_leds(void);
void init_buzzr(int);
void init_switch(void);
void init_motor(void);
#endif

324
firmware/lib/synth.c Normal file
View File

@ -0,0 +1,324 @@
#include <inttypes.h>
#include "synth.h"
#include "freq_table.h"
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
// sample rate is 8M / (3 * 64)
enum {
channel_count = 3,
//tick_length = 400,
// tick_length = 256,
row_length = 4,
pattern_length = 16
};
static const synth_instrument_t instruments[] = {
{ 1<<15, 100, 12 },
{ 0, 100, 12 },
{ 0, 200, 10 },
{ 1<<13, 0, 0, 2 },
{ 1<<13, 0, 5, 2 },
};
static const uint8_t wave_table[][2] = {
{ 0, WAVE_PULSE },
{ 3, WAVE_PULSE },
{ 7, WAVE_PULSE },
{ 12, WAVE_PULSE },
{ 256 - 4, 0xff },
{ 0, WAVE_PULSE },
{ 2, WAVE_PULSE },
{ 7, WAVE_PULSE },
{ 10, WAVE_PULSE },
{ 256 - 4, 0xff },
{ 0, WAVE_NOISE },
{ 0, WAVE_PULSE },
{ 0xff, 0xff },
{ 0, WAVE_PULSE },
{ 0xff, 0xff },
};
static const uint8_t patterns[][pattern_length][2] PROGMEM = {
{},
{
{ 33 - 12, 0 },
{ 0, 0 },
{ 0xff, 1 },
{ 0, 0 },
{ 33, 1 },
{ 0xff, 1 },
{ 33, 1 },
{ 0xff, 1 },
{ 33, 1 },
{ 0xff, 1 },
{ 33 - 12, 1 },
{ 0xff, 1 },
{ 33 - 12, 1 },
{ 0xff, 1 },
{ 33, 1 },
{ 0xff, 1 },
},
{
{ 28 - 12, 0 },
{ 0, 0 },
{ 0xff, 1 },
{ 0, 0 },
{ 28, 1 },
{ 0xff, 1 },
{ 28, 1 },
{ 0xff, 1 },
{ 28, 1 },
{ 0xff, 1 },
{ 28 - 12, 1 },
{ 0xff, 1 },
{ 28 - 12, 1 },
{ 0xff, 1 },
{ 28, 1 },
{ 0xff, 1 },
},
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 57, 3 },
},
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 57, 4 },
},
{
{ 60, 2 },
},
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 57, 2 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 55, 2 },
{ 0, 0 },
{ 57, 2 },
{ 0, 0 },
},
{
{ 55, 2 },
},
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 57, 2 },
},
{
{ 55-3, 2 },
},
};
static const uint8_t pattern_table[][channel_count] = {
{ 1, 0, 5 },
{ 1, 3, 0 },
{ 1, 0, 7 },
{ 1, 3, 6 },
{ 2, 0, 7 },
{ 2, 4, 8 },
{ 2, 0, 9 },
{ 2, 4, 0 },
};
enum {
pattern_table_length = sizeof(pattern_table) / sizeof(pattern_table[0])
};
static synth_channel_t channels[channel_count];
static int8_t sample;
static int8_t tick;
static int8_t row;
static int8_t seq;
/* PROTOTYPES */
uint8_t synth_mix(void);
static uint8_t timeslots[SYNTH_BUFSIZE];
static uint8_t timeslots_write; // current write head
static uint8_t timeslots_read; // current read head
/*register for atomic ++ and -- */
register uint8_t timeslots_fill asm("r2");
static void enqueue_timeslot(uint8_t synthval);
static uint8_t dequeue_timeslot(void);
void synth_init(void)
{
sample = 0;
tick = 0;
row = 0;
seq = 0;
timeslots_fill = 0;
}
inline uint8_t synth_mix(void)
{
if(sample == 0) { // new tick
for(int i = 1; i < channel_count; i++) {
synth_channel_t* chan = &channels[i];
const synth_instrument_t* inst = &instruments[chan->inst_nr];
if(chan->level > inst->decay) chan->level -= inst->decay;
else chan->level = 0;
chan->pulse_width += inst->pulse_sweep;
chan->pos++;
if(wave_table[chan->pos][1] == 0xff) chan->pos += wave_table[chan->pos][0];
// enter new rol
// w
if(tick == 0) {
uint8_t pattern_nr = pattern_table[seq][i];
uint8_t note = pgm_read_byte(&patterns[pattern_nr][row][0]);
if(note) { // new note, maybe?
if(note == 0xff) {
chan->level = 0;
} else {
chan->level = 80; // TODO: less?
chan->note = note;
chan->inst_nr = pgm_read_byte(&patterns[pattern_nr][row][1]);
inst = &instruments[chan->inst_nr];
chan->pos = inst->wave_table_pos;
if(inst->pulse_width) chan->pulse_width = inst->pulse_width;
}
}
}
}
}
if(++sample == 0){
if(++tick == row_length) {
tick = 0;
if(++row == pattern_length) {
row = 0;
if(++seq == pattern_table_length) {
seq = 0;
}
}
}
}
uint8_t output = 0;
for(int i = 0; i < channel_count; i++) {
synth_channel_t* chan = &channels[i];
// const synth_instrument_t* inst = &instruments[chan->inst_nr];
chan->phase += pgm_read_word(&freq_table[(uint8_t)(chan->note + wave_table[chan->pos][0])]);
uint8_t amp;
switch(wave_table[chan->pos][1]) {
case WAVE_PULSE:
amp = -(chan->phase < chan->pulse_width);
break;
case WAVE_SAW:
amp = (chan->phase >> 8);
break;
case WAVE_NOISE: // shitty noise
chan->phase = (chan->phase >> 1) ^ (-(chan->phase & 1) & 0xb400);
amp = (chan->phase >> 8);
break;
default:
amp = 0;
break;
}
output += (((amp & 0xff) * chan->level) >> 8);
}
return output;
}
/* fill all the timeslots */
inline void synth_poll(void) {
/* refill timeslots queue */
// while (timeslots_fill < (SYNTH_BUFSIZE-1))
if (timeslots_fill < (SYNTH_BUFSIZE-1))
enqueue_timeslot(synth_mix());
}
/* timeslot queue handling */
static inline void enqueue_timeslot(uint8_t synthval) {
timeslots[timeslots_write & SYNTH_BUFMASK] = synthval;
timeslots_fill++;
timeslots_write++;
}
static inline uint8_t dequeue_timeslot() {
uint8_t t = timeslots[timeslots_read & SYNTH_BUFMASK];
if(timeslots_fill){
/* buffer not underrun... move forward in readbuffer */
timeslots_fill --;
timeslots_read ++;
}
return t;
}
ISR(TIMER0_COMPA_vect)
{
/* calculate next analog sample value in synth mixer:*/
OCR1B = dequeue_timeslot();
}

34
firmware/lib/synth.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef SYNTH_H
#define SYNTH_H
#define SYNTH_BUFSIZE (16)
#define SYNTH_BUFMASK (0b00001111)
enum { WAVE_OFF, WAVE_PULSE, WAVE_SAW, WAVE_NOISE };
typedef struct {
uint8_t note;
uint8_t inst_nr;
uint8_t pos;
uint16_t phase;
uint16_t pulse_width;
uint8_t level; // envelop level
} synth_channel_t;
typedef struct {
uint16_t pulse_width;
uint8_t pulse_sweep;
uint8_t wave_table_pos;
uint8_t decay;
} synth_instrument_t;
void synth_init(void);
void synth_poll(void);
#endif

136
firmware/lib/usart.c Normal file
View File

@ -0,0 +1,136 @@
/*
* PentaFnord Firmware
*
* by Alexander Lorz <bigalex@gmx.de>
*
*
* The USART control code is derived by code from the 4CHLED project
* by sebseb7: https://github.com/sebseb7/eagle/tree/master/4CHLED/firmware
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
//#include "main.h"
#include "usart.h"
#define UART_RXBUFSIZE 32
volatile static uint8_t rxbuf0[UART_RXBUFSIZE];
volatile static uint8_t *volatile rxhead0, *volatile rxtail0;
//volatile uint8_t xon = 0;
ISR (USART_RX_vect)
{
UCSR0B &= ~(1 << RXCIE0);
asm volatile("sei");
int diff;
uint8_t c;
c=UDR0;
diff = rxhead0 - rxtail0;
if (diff < 0) diff += UART_RXBUFSIZE;
if (diff < UART_RXBUFSIZE -1)
{
*rxhead0 = c;
++rxhead0;
if (rxhead0 == (rxbuf0 + UART_RXBUFSIZE)) rxhead0 = rxbuf0;
// if((diff > 100)&&(xon==0))
// {
// xon=1;
// //set the CTS pin
// }
}
UCSR0B |= (1 << RXCIE0);
}
void USART0_Init (void)
{
// set baudrate
#undef BAUD
#define BAUD 115200
#include <util/setbaud.h><util/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
//#if USE_2X
UCSR0A |= (1 << U2X0); // enable double speed operation
//#else
// UCSR0A &= ~(1 << U2X0); // disable double speed operation
//#endif
// flush receive buffer
while ( UCSR0A & (1 << RXC0) ) UDR0;
// set 8N1
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR0B &= ~(1 << UCSZ02);
UCSR0B |= (1 << RXEN0)|(1 << TXEN0); //enable send and receive
UCSR0B |= (1 << RXCIE0); //enable receive interrup
rxhead0 = rxtail0 = rxbuf0;
}
void USART0_putc (char c)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
}
uint8_t USART0_Getc_nb(uint8_t *c)
{
if (rxhead0==rxtail0) return 0;
*c = *rxtail0;
if (++rxtail0 == (rxbuf0 + UART_RXBUFSIZE)) rxtail0 = rxbuf0;
// uint8_t diff = rxhead0 - rxtail0;
// if((diff < 10)&&(xon==1))
// {
// xon=0;
// //set the CTS pin
// }
return 1;
}
void USART0_crlf(){
USART0_putc(0x0A); //newline
USART0_putc(0x0D); //carriage return
};
void USART0_put_uint8(uint8_t x){
uint8_t highchar=((x & 0b11110000)>>4)+0x30;
uint8_t lowchar = (x & 0b00001111)+0x30;
highchar = highchar>0x39 ? highchar + 0x07 : highchar; //chars A to F start with 0x41 not 0x3A
lowchar = lowchar>0x39 ? lowchar + 0x07 : lowchar;
USART0_putc(highchar);
USART0_putc(lowchar);
}
void USART0_put_uint16(uint16_t x){
USART0_put_uint8 ((x & 0xFF00)>>8);
USART0_put_uint8 (x & 0x00FF);
}

34
firmware/lib/usart.h Normal file
View File

@ -0,0 +1,34 @@
/*
* PentaFnord Firmware
*
* by Alexander Lorz <bigalex@gmx.de>
*
*
* The USART control code is derived by code from the 4CHLED project
* by sebseb7: https://github.com/sebseb7/eagle/tree/master/4CHLED/firmware
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _USART_H
#define _USART_H
void USART0_Init (void);
void USART0_putc (char c);
uint8_t USART0_Getc_nb(uint8_t*);
void USART0_put_uint8(uint8_t);
void USART0_crlf();
void USART0_put_uint16(uint16_t);
#endif

View File

@ -49,29 +49,6 @@ static inline void init_pwm(void)
return;
}
static void init_leds(void)
{
/* enable LED channels as output */
DDRC |= (1 << PORTC0) | (1 << PORTC2) |
(1 << PORTC3) | (1 << PORTC1) ;
/* initially one led is on */
PORTC = 0b00000101;
/*
* Timer 2
*/
/* set timer2 to CTC & prescaler 64 → ???125kHz increment */
TCCR2A = (1 << WGM21);
TCCR2B = (1 << CS20)|(1 << CS21);
OCR2A = 255; /* TOP */
TCNT2 = 0;
/*enable interrupt*/
TIMSK2 |= (1<<OCIE2A);
return;
}
inline void setleds(uint8_t state)
{
@ -81,13 +58,6 @@ inline void setleds(uint8_t state)
return;
}
static void init_motor(void)
{
/* vibration motor on B1, initially off: */
DDRB |= (1 << PORTB1);
PORTB &= ~( 1<<PORTB1);
return;
}