From: Jan "Yenya" Kasprzak Date: Sun, 13 Jul 2014 14:48:08 +0000 (+0200) Subject: Initial commit X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=kolektor.git;a=commitdiff_plain;h=17cbca493bd2ecc9317b7b934e7a2807c5212c4c Initial commit --- 17cbca493bd2ecc9317b7b934e7a2807c5212c4c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4f14c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +eeprom.raw +kolektor.eep +kolektor.elf +kolektor.hex +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1c0c503 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +PROGRAM=kolektor +SRC=main.c logging.c +OBJ=$(SRC:.c=.o) + + +MCU=attiny25 +AVRDUDE_MCU=$(MCU) +AVRDUDE_PROGRAMMER=usbasp + +CFLAGS=-Wall -Os -mmcu=$(MCU) -DUSE_LOGGING=1 -DF_CPU=1000000UL -std=gnu99 +LDFLAGS= +AVRDUDE_FLAGS= -p$(AVRDUDE_MCU) -B 4 -c $(AVRDUDE_PROGRAMMER) + +FORMAT=ihex + +CC=avr-gcc +OBJCOPY=avr-objcopy +OBJDUMP=avr-objdump +AVRDUDE=avrdude + +all: $(PROGRAM).hex $(PROGRAM).eep + +program: $(PROGRAM).hex $(PROGRAM).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(PROGRAM).hex:i -U eeprom:w:$(PROGRAM).eep:i + +program_flash: $(PROGRAM).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(PROGRAM).hex:i + +program_eeprom: $(PROGRAM).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) eeprom:w:$(PROGRAM).eep:i + +dump_eeprom: + $(AVRDUDE) $(AVRDUDE_FLAGS) -U eeprom:r:eeprom.raw:r + od -tx1 eeprom.raw + +objdump: $(PROGRAM).elf + $(OBJDUMP) --disassemble $< + +.PRECIOUS : $(OBJ) $(PROGRAM).elf + +%.hex: %.elf + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +%.elf: $(OBJ) + $(CC) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS) + +%.o: %.c Makefile + $(CC) -c $(CFLAGS) $< -o $@ + +%.s: %.c Makefile + $(CC) -S -c $(CFLAGS) $< -o $@ + +%.o: %.S + $(CC) -c $(CFLAGS) $< -o $@ + +clean: + rm -f $(PROGRAM).hex $(PROGRAM).eep $(PROGRAM).elf *.o *.s eeprom.raw + +.PHONY: all clean dump_eeprom program program_flash program_eeprom objdump + diff --git a/POPIS b/POPIS new file mode 100644 index 0000000..5dfeb58 --- /dev/null +++ b/POPIS @@ -0,0 +1,57 @@ +Dokumentace k desce +=================== +(schéma, layout plošného spoje): +http://www.fi.muni.cz/~kas/tinyboard/ + +Osazení desky: +============== + +U1: ATtiny25-20SSU +U2: MCP1703T-500 regulátor napětí 5V, 250 mA +Q20, Q50: N-MOSFET IRLML6344TRPBF, 30V, 5A +C1, C3: 10uF keramické, typ nevím :-) +C2, R10, R30, R40: _kondenzátory_ 220nF keramické X7R +R12, R20, R32, R42, R50: odpory 15KOhm +R34, R44: odpory 300KOhm (podle nich dimenzovat termistory) +D50, R15, R21, R23, R51, R53: propjky 0 Ohm (nebo dráty) + +Nepoužito: +R2, R3, R4, R11, R13, R14, R22, R24, R25, R31, R33, R41, R43, R45, R52, R54, R55 +C11, C51, D10, L10, L50, Q10, Q1, Q2, Q30, Q40, U3 + +Možno ještě osadit kontrolku napájení (D1, R1) + +Přiřazení pinů ATtiny: +====================== +PB0: plovák nebo jiný spínač, zapojit mezi piny 1 a 2 konektoru PB0 +PB1: ovládání motoru, zapojit mezi piny 2 a 3 konektoru PB1 +PB2: termistor, zapojit mezi piny 1 a 2+3 konektoru PB2 +PB3: termistor, zapojit mezi piny 1 a 2+3 konektoru PB3 +PB4: ovládání motoru, zapojit mezi piny 2 a 3 konektoru PB4 + +Motory lze řídit i přes PWM (viz dokumentace Timer/Counter 1, +pin PB1 je pak OC1A, pin PB4 je OC1B. Doporučuju T/C1 časovat z PLL clock +na 32 MHz, čímž se získá PWM o frekvenci 256 kHz, což by mělo na plynulé +řízení motoru stačit. + +Termistory jsou čitelné přes A/D převodník (PB2 je ADC1, PB3 je ADC2). +Podle typu termistoru použít vhodnou napěťovou referenci ADC (asi interní 1.1V). +Před vstupem PB0, PB2 a PB3 je low-pass filtr z 220nF kondenzátoru +a 15k odporu, což by mělo ořezávat frekvence vyšší než cca 50 Hz. +Tentýž kanál ADC tedy nemá smysl vyhodnocovat častěji. + +Možná půjde využít i vestavěný teploměr (viz dokumentace A/D převodníku). + +Programování: +============= +Před programováním odpojit piny PB0-PB2 od zbytku desky vyndáním jumperů J1-J3. + +make program # přeloží firmware a nakopíruje do CPU (flash+eeprom) +make program_flash # totéž, uploaduje jen programovou paměť (flash) +make program_eeprom # totéž, uploaduje jen eeprom +make dump_eeprom # výpis eeprom, například logovacích dat + +Programová flash umožňuje 10_000 přepsání (OK), EEPROM umožňuje +"jen" 100_000 přepsání (pozor na to při logování do EEPROM, ať se +příliš často nepřepisuje ta stejná adresa, například při zacyklení programu). + diff --git a/attiny25.pdf b/attiny25.pdf new file mode 100644 index 0000000..3feb1ec Binary files /dev/null and b/attiny25.pdf differ diff --git a/irlml6344trpbf.pdf b/irlml6344trpbf.pdf new file mode 100644 index 0000000..550db37 Binary files /dev/null and b/irlml6344trpbf.pdf differ diff --git a/logging.c b/logging.c new file mode 100644 index 0000000..a69162a --- /dev/null +++ b/logging.c @@ -0,0 +1,77 @@ +#include +#include + +#include "logging.h" + +#define LOG_BUFFER 32 +static unsigned char log_buffer_ee[LOG_BUFFER] EEMEM; +static unsigned char log_buffer_count; +static unsigned char log_buffer[LOG_BUFFER]; +static unsigned char log_state EEMEM; +/* Upper 4 bits are reset count, lower 4 bits are reset reason from MCUSR */ +static unsigned char reboot_count EEMEM = 0; +static unsigned char can_write_eeprom = 0; +static uint16_t flushed_end; + +void log_set_state(unsigned char val) +{ + if (can_write_eeprom) + eeprom_write_byte(&log_state, val); +} + +void init_log() +{ + unsigned char r_count; + + r_count = eeprom_read_byte(&reboot_count); + r_count >>= 4; + + if (r_count < 5) { + r_count++; + eeprom_write_byte(&reboot_count, + (r_count << 4) | (MCUSR & 0xF)); + MCUSR = 0; + can_write_eeprom = 1; + } else { + //eeprom_write_byte(&log_state, 0xFF); + can_write_eeprom = 0; + } + + log_set_state(1); + log_buffer_count = 0; + flushed_end = 0; +} + +void log_byte(unsigned char byte) { + if (log_buffer_count >= LOG_BUFFER) + return; + + // eeprom_write_word(&log_buffer[log_buffer_count], word); + log_buffer[log_buffer_count++] = byte; + + if (log_buffer_count == LOG_BUFFER) + log_flush(); +} + +void log_word(uint16_t word) { + log_byte(word & 0xFF); + log_byte(word >> 8); +} + +void log_flush() { + unsigned char i; + + if (!can_write_eeprom) + return; + + for (i=flushed_end; i < log_buffer_count; i++) { + eeprom_write_byte(&log_buffer_ee[i], + log_buffer[i]); + } + + flushed_end = i; + + if (flushed_end == LOG_BUFFER) + log_set_state(0x42); +} + diff --git a/logging.h b/logging.h new file mode 100644 index 0000000..2b71809 --- /dev/null +++ b/logging.h @@ -0,0 +1,10 @@ +#ifndef LOGGING_H__ +#define LOGGING_H__ 1 + +void init_log(); +void log_set_state(unsigned char val); +void log_flush(); +void log_byte(unsigned char byte); +void log_word(uint16_t word); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..0fbb919 --- /dev/null +++ b/main.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include "logging.h" + +// init PLL clock for timer/counter 1 +// datasheet sekce 12.2.1 +static void enable_pll_clock() +{ + // async clock + PLLCSR = _BV(PLLE) | _BV(LSM); // low-speed mode (32 MHz) + + // Synchronize to the phase lock + _delay_us(100); + while((PLLCSR & _BV(PLOCK)) == 0) + ; + PLLCSR |= _BV(PCKE); +} + +// Timer/Counter 1 initialization +// datasheet sekce 12 +static void init_tc1() +{ + power_timer1_enable(); + + TCCR1 = _BV(CTC1) // clear on compare match + | _BV(CS10) // clock = PCK (no divisor) + | _BV(COM1A1) // clear output line on compare match + | _BV(PWM1A); // PWM mode + + OCR1C = 255; // TOP value + + DDRB |= _BV(PB1); + OCR1A = 0; // stride + + // Tohle pripadne povoli PWM i na OC1B (PB4) + // GTCCR = _BV(COM1B1) | _BV(PWM1B); + // DDRB |= _BV(PB4); + // OCR1B = 0; // stride +} + +// precte synchronne (busy-waitem) jednu hodnotu z A/D prevodniku +static uint16_t read_adc_sync() +{ + uint16_t rv; + + ADCSRA |= _BV(ADSC); // start the conversion + + // wait for the conversion to finish + while((ADCSRA & _BV(ADIF)) == 0) + ; + + rv = ADCW; + ADCSRA |= _BV(ADIF); // clear the IRQ flag + + return rv; +} + +// analog to digital converter +// datasheet sekce 17 +static void init_adc() +{ + power_adc_enable(); + ACSR |= _BV(ACD); // enable ADC, disable AC + + ADCSRA = _BV(ADEN) // enable + | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz + ; + + DIDR0 = _BV(ADC1D) | _BV(ADC3D); // disable dig. input on ADC1, ADC3 (PB2, PB3) + ADMUX = _BV(REFS1) // 1.1V internal reference + | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0) // ADC4 (temperature) + ; + + // do the first conversion, drop the result + read_adc_sync(); +} + +int main(void) +{ + unsigned char i; + + init_log(); + + log_byte(0x42); // zkouska logovani + log_flush(); // nezapomenout vylit buffer + + power_all_disable(); /* vypneme cele I/O, pak zapneme co bude potreba */ + + DDRB |= _BV(DDB4); // PB4 as output + + enable_pll_clock(); + init_tc1(); + init_adc(); + + // po skonceni inicializace muzeme i zapnout preruseni, + // pokud je budeme potrebovat + // cli(); + + // priklad prace s A/D prevodnikemo + // init_adc() necha ADMUX nastaveny na ADC4 (teplomer), jinak + // tady lze ADMUX prestavit na neco jineho (pozor na napetovou + // referenci REFS) + log_word(read_adc_sync()); // nacteme teplotu, zalogujeme + // interpretace vysledku: datasheet sekce 17.12 + log_flush(); + + while(1) { + for (i = 0; i < 16; i++) { + // zapiname/vypiname portb4 v sudem/lichem kroku + if (i & 1) { + PORTB |= _BV(PORTB4); + } else { + PORTB &= ~_BV(PORTB4); + } + + // hodnopta PWM pro PB1 (OC1A) + // jdeme od 128 do 248, napriklad: + OCR1A = 0x80 + (i << 3); + + // busy-wait, nebo se muzeme nechat casovat + // pomoci watchdogu (WDT, datasheet sekce 7.4.5) + // nebo pomoci Timer/Counter 0 (datasheet sekce 11) + _delay_ms(1500); + } + } +} diff --git a/mcp1703.pdf b/mcp1703.pdf new file mode 100644 index 0000000..a522b76 Binary files /dev/null and b/mcp1703.pdf differ