; ; audiomega3-sampler ; ; Audio sampler ; .include "m88def.inc" ;.device ATmega88 ; ; dataflash ; ; read .equ CONTINUOUS_ARRAY_READ = 0xE1 .equ MAIN_MEMORY_PAGE_READ = 0xD2 .equ BUFFER_READ = 0xD4 .equ STATUS_REGISTER_READ = 0xD7 ; write .equ BUFFER_WRITE = 0x84 .equ BUFFER_TO_MAIN_MEMORY_PAGE_PROGRAM_WITH_ERASE = 0x83 .equ BUFFER_TO_MAIN_MEMORY_PAGE = 0x88 .equ PAGE_ERASE = 0x81 .equ BLOCK_ERASE = 0x50 .equ MAIN_MEMORY_PAGE_PROGRAM_THROUGH_BUFFER = 0x82 ; additional .equ MAIN_MEMORY_PAGE_TO_BUFFER_TRANSFER = 0x53 .equ MAIN_MEMORY_PAGE_TO_BUFFER_COMPARE = 0x60 .equ AUTO_PAGE_REWRITE_THROUGH_BUFFER = 0x58 ; properties .equ PAGE_COUNT = 512 .equ BUFFER_COUNT = 264 ; ; definitions ; .equ tx = PD1; transmit pin .equ tx_port = PORTD .equ tx_ddr = DDRD .equ led1 = PC5 .equ led1_port = PORTC .equ led1_ddr = DDRC .equ led2 = PD5 .equ led2_port = PORTD .equ led2_ddr = DDRD .equ but1 = PD6 .equ but1_port = PORTD; .equ but1_ddr = DDRD; .equ but1_pin = PIND; .equ but2 = PD7 .equ but2_port = PORTD; .equ but2_ddr = DDRD; .equ but2_pin = PIND; .equ cs = PB2 .equ cs_port = PORTB; .equ cs_ddr = DDRB; .equ mosi = PB3 .equ mosi_port = PORTB .equ mosi_ddr = DDRB .equ miso = PB4 .equ miso_port = PORTB .equ miso_ddr = DDRB .equ sck = PB5 .equ sck_port = PORTB .equ sck_ddr = DDRB ; ; registers ; .def bit_count = R16; bit counter .def temp = R17; temporary storage .def temp1 = R18; temporary storage .def txbyte = R19; data byte .def spi_byte = R20; .def flash_byte = R21; .def flash_page_low = R22 .def flash_page_high = R23 .def buffer_count_low = R24 .def buffer_count_high = R25 ; ; code segment ; .cseg .org 0 rjmp reset ; ; bit delay ; serial bit delay ; ;.equ b = 13 ; 9600 baud (clock /8) ;.equ b = 130 ; 9600 baud (clock /1) .equ b = 8 ; 115200 baud (clock /1) bit_delay: ldi temp, b bitloop: dec temp brne bitloop ret ; ; putchar ; assumes no line driver (doesn't invert bits) ; .equ sb = 1; number of stop bits putchar: ldi bit_count, 9+sb; 1+8+sb com txbyte; invert everything sec; set start bit putchar0: brcc putchar1; if carry set sbi tx_port, tx; send a '0' rjmp putchar2; else putchar1: cbi tx_port, tx ; send a '1' nop ; even out timing putchar2: rcall bit_delay; one bit delay rcall bit_delay lsr txbyte; get next bit dec bit_count; if not all bits sent brne putchar0; send next bit ret; ; ; char_delay ; delay between characters ; char_delay: ldi temp, 255 char_delay_loop: ldi temp1, 10 char_delay_loop1: dec temp1 brne char_delay_loop1 dec temp brne char_delay_loop ret ; ; Write data to SPI ; write_spi: out SPDR, spi_byte wait_for_transmit: in temp, SPSR sbrs temp, SPIF rjmp wait_for_transmit ret read_spi: wait_for_read: in temp, SPSR sbrs temp, SPIF rjmp wait_for_read in spi_byte, SPSR ret ; ; wait until flash free ; wait_for_flash: wait_for_flash_loop: ldi spi_byte, STATUS_REGISTER_READ rcall write_spi rcall read_spi sbrc spi_byte, 7 ; check busy status in flash status register rjmp wait_for_flash_loop ; ; Put flash pointer to 0 ; reset_flash_pointer: ldi flash_page_low, 0 ldi flash_page_high, 0 ret ; ; Write adc data to flash (aka, record) ; record: ; turn on record led rcall reset_flash_pointer record_loop: cbi cs_port, cs ; enable DataFlash ldi spi_byte, MAIN_MEMORY_PAGE_PROGRAM_THROUGH_BUFFER rcall write_spi ; bits: xxxxxx11 11111110 00000000 ; ^res ^^page pos^^buff pos^ mov temp, flash_page_low mov temp1, flash_page_high rol temp rol temp1 mov spi_byte, temp rcall write_spi mov spi_byte, temp1 rcall write_spi ldi spi_byte, 0 rcall write_spi ldi buffer_count_low, 0 ldi buffer_count_high, 0 adc_loop: lds temp, ADCSRA sbr temp, (1 << ADSC) sts ADCSRA, temp ; start conversion adloopup: lds temp, ADCSRA sbrc temp, ADSC ; loop until settled rjmp adloopup lds spi_byte, ADCH ; hi byte - left adjusted, 8 bit res. rcall write_spi inc buffer_count_low brcc inc_done inc buffer_count_high inc_done: cpi buffer_count_low, low(BUFFER_COUNT) ldi temp, high(BUFFER_COUNT) cpc buffer_count_high, temp brlo adc_loop sbi cs_port, cs ; Cause buffer to write to page. inc flash_page_low brcc post_flash_page_inc inc flash_page_high post_flash_page_inc: cpi flash_page_low, low(PAGE_COUNT) ldi temp, high(PAGE_COUNT) cpc flash_page_high, temp brlo loopup brsh return loopup: ;rcall wait_for_flash ; delay until not busy with prev write cbi led2_port, led2 ; *#&$(*@#&$ rjmp record_loop return: ; turn off record led sbi led2_port, led2 ret playback: ; turn off record led cbi led1_port, led1 ldi spi_byte, CONTINUOUS_ARRAY_READ rcall write_spi ldi spi_byte, 0 ; 24 address bits: rcall write_spi rcall write_spi rcall write_spi ; 32 don't care bits rcall write_spi rcall write_spi rcall write_spi rcall write_spi playback_loop: rcall read_spi sts OCR2B, spi_byte ldi temp, 255 sample_delay: dec temp brne sample_delay sbis but2_pin, but2 rjmp playback_loop ; turn off playback led sbi led1_port, led1 ldi temp, 0 sts OCR2B, temp ret ; ; main program ; reset: ; ; set clock divider to /1 ; ldi temp, (1 << CLKPCE) ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0) sts CLKPR, temp sts CLKPR, temp1 ; ; set up SPI for dataflash ; ; interrupts off, spi enabled, master mode, data order MSB first, SPI mode 3, clock/4 ldi temp,(0 << SPIE) | (1 << SPE) | (1 << MSTR) | (0 << DORD) | (1 << CPOL) | (1 << CPHA) | (0 << SPR1) | (0 << SPR0) out SPCR, temp ; ; set stack pointer to top of RAM ; ldi temp, high(RAMEND) out SPH, temp ldi temp, low(RAMEND) out SPL, temp ; ; init pins ; sbi tx_ddr, tx sbi tx_port, tx sbi led1_ddr, led1 sbi led1_port, led1 sbi led2_ddr, led2 sbi led2_port, led2 cbi but1_ddr, but1 sbi but1_port, but1 cbi but2_ddr, but2 sbi but2_port, but2 ; SPI sbi sck_ddr, sck cbi miso_ddr, miso sbi mosi_ddr, mosi sbi cs_ddr, cs sbi sck_port, sck sbi miso_port, miso sbi mosi_port, mosi sbi cs_port, cs ; ; ADC ; lds temp, ADMUX cbr temp, (1 << REFS1) ; use external AREF reference cbr temp, (1 << REFS0) ; sbr temp, (1 << ADLAR) ; left-adjust result cbr temp, (1 << MUX3) ; single-ended input on ADC0 (PC0) cbr temp, (1 << MUX2) ; cbr temp, (1 << MUX1) ; cbr temp, (1 << MUX0) ; sts ADMUX, temp lds temp, ADCSRA sbr temp, (1 << ADEN) ; enable A/D cbr temp, (1 << ADATE) ; disable auto-trigger cbr temp, (1 << ADIE) ; disable interrupts sbr temp, (1 << ADPS2) ; set prescaler for /16 cbr temp, (1 << ADPS1) ; " cbr temp, (1 << ADPS0) ; " sts ADCSRA, temp lds temp, PRR cbr temp, (1 << PRADC) ; disable power reduction on ADC sts PRR, temp ; ; PWM ; ldi temp, ((1 << COM2B0) | (1 << COM2B1) | (1 << WGM21) | (1 << WGM20)) sts TCCR2A, temp ; set OC2B on compare match and fast PWM mode, 0xFF TOP ldi temp, (1 << CS00) sts TCCR2B, temp ; set timer 0 prescalar to 1 sbi DDRD, PD3 ; enable OC2B output pin cbi PORTD, PD3 ; ; main loop ; main_loop: sbis but1_pin, but1 rjmp record sbis but2_pin, but2 rjmp playback rjmp main_loop