]> www.fi.muni.cz Git - kolektor.git/commitdiff
Initial commit
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sun, 13 Jul 2014 14:48:08 +0000 (16:48 +0200)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sun, 13 Jul 2014 14:48:08 +0000 (16:48 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
POPIS [new file with mode: 0644]
attiny25.pdf [new file with mode: 0644]
irlml6344trpbf.pdf [new file with mode: 0644]
logging.c [new file with mode: 0644]
logging.h [new file with mode: 0644]
main.c [new file with mode: 0644]
mcp1703.pdf [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e4f14c5
--- /dev/null
@@ -0,0 +1,5 @@
+eeprom.raw
+kolektor.eep
+kolektor.elf
+kolektor.hex
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 (file)
index 0000000..3feb1ec
Binary files /dev/null and b/attiny25.pdf differ
diff --git a/irlml6344trpbf.pdf b/irlml6344trpbf.pdf
new file mode 100644 (file)
index 0000000..550db37
Binary files /dev/null and b/irlml6344trpbf.pdf differ
diff --git a/logging.c b/logging.c
new file mode 100644 (file)
index 0000000..a69162a
--- /dev/null
+++ b/logging.c
@@ -0,0 +1,77 @@
+#include <avr/io.h>
+#include <avr/eeprom.h>
+
+#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 (file)
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 (file)
index 0000000..0fbb919
--- /dev/null
+++ b/main.c
@@ -0,0 +1,130 @@
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+
+#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 (file)
index 0000000..a522b76
Binary files /dev/null and b/mcp1703.pdf differ