; DCM.asm - Source code for COMATOS Real Time Operating System Tutorial ; Ben Greenblatt, 10/18 ; NOTE TO USER: NEVER USE r16-r18 or Z as a destination register for OS calls .nolist .include "8515def.inc" .include "comtapi.inc" .list ; Task Number Definitions .equ KbdTask=0 .equ MeasureTask=1 .equ DisplayTask=2 .equ CapIsr=3 ; Measurement State Definitions .equ keyWait =0 .equ dischargeWait =1 .equ measureWait =2 .def key =r17 ;holds raw press value .def butnum =r18 ;final press value .def state =r19 ;debounce state .def lastKey =r20 ;last keypress .def Temp =r21 ;temporary register .def capacit =r19 ;capacitance value .equ waitState=0 .equ gotKeyState=1 .equ TIMSKVal=0x08 ; Only use input capture .equ TCCR1BVal=0b01000011 ; Capture on rising edge, 64x clock div .equ ACSRVal=0b00000111 ; Interrupt enable, rising edge, input capture .cseg .org $0000 rjmp RESET ;reset entry vector reti reti rjmp T1CapISR reti reti reti rjmp OST0ISR reti reti rjmp OSTXISR ;UART buffer empty reti reti .include "comtf.inc" keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111 .db 0b11011110, 0b11011101, 0b11011011, 0b11010111 .db 0b10111110, 0b10111101, 0b10111011, 0b10110111 .db 0b01111110, 0b01111101, 0b01111011, 0b01110111 capMessage: .db "The capacitance in nF is:" RESET: ldi r20, LOW(RAMEND) ;setup stack pointer out SPL, r20 ldi r20, HIGH(RAMEND) out SPH, r20 OSInit 30, OSDebug ; Specifies 30 ms timeout and debugging features ; Setup timer 1 ldi r16, (TIMSKVal | TimerMask) out TIMSK, r16 ; Setup analog comparator ldi r16, ACSRVal out ACSR, r16 ; Setup PortB for analog comparator ldi r16, 0b11110011 ; Make most pins output except comparator out DDRB, r16 clr r16 out PORTB, r16 ; Start discharging OSCreateTask KbdTaskF, 30, 0xff ; Can't run unless timeout since ; mask is 0xff OSCreateTask MeasureTaskF, 0x00, 0x01 ; Initially can't run unless ; it gets a message from the keyboard OSCreateTask DisplayTaskF, 0x00, 0x02 ; No timeout, wait for message from measurement OSStart halt: rjmp halt ; Pulls a key from the keyboard, debounces it, and sends it to the measurement ; task KbdTaskF: OSGetState state ; get the current state ; Get the key press ldi temp, 0x0f ;set lower four lines to output out DDRC, temp ldi temp, 0xf0 ;and turn on the pullups on the inputs out PORTC, temp nop ;Need some time for the pullups to nop ;charge the port pins nop nop in temp, PINC ;read the high nibble mov key, temp ;and store it (with zeros in the low nibble) ldi temp, 0xf0 ;set upper four lines to outputs out DDRC, temp ldi temp, 0x0f ;and turn on pullups on the inputs out PORTC, temp nop ;As before wait for the pin to charge nop nop nop in temp, PINC ;read the low nibble or key, temp ;combine to make key code ;At the point the raw key code should have exactly one zero each in ;the lower and upper nibbles. Any other number of zeros indicates ;either no-button pressed or multiple-button pressed. ;Now search the table for a match to the raw key code ;and exit with a button number ldi ZL, low(keytbl*2) ;table pointer in FLASH ldi ZH, high(keytbl*2) ;so convert from word to byte addr ldi butnum, 0 tbllp: lpm ;get the table entry cp key, r0 ;match? breq foundit inc butnum ;if not, have we exhaused the cpi butnum, 0x10 ;table breq illegal adiw ZL, 1 ;if not, get the next table entry rjmp tbllp foundit:subi butnum, -1 ;add one for display rjmp TT1_statematch illegal:clr butnum TT1_statematch: OSGetMess lastKey, 0 ;Last key press is stored in our own mailbox tst state ;Check the state breq TT1_state_0 TT1_state_1: OSSetState 0 ; Return state to zero cp lastKey, butnum ; Compare the key presses breq TT1_debounce ; Key is debounced rjmp TT1_false ; False alarm TT1_debounce: tst butnum breq TT1_release OSSendMess butnum, measureTask; Send the key press to the measurement task TT1_release: OSReturn 0 TT1_state_0: cp lastKey, butnum ; Compare the key presses brne TT1_newKey OSReturn 0 TT1_newKey: OSSetState gotKeyState ; New key press OSSendMess butnum, 0 ; Store the last button press OSReturn 0 TT1_false: OSSetState 0 OSReturn 0 MeasureTaskF: ; If we did not get a message from the keyboard ; something is wrong OSGetMessageSrc Temp ; Get the list of who sent us messages andi Temp, exp2(kbdTask) brne MT_startDischarge OSReturn 1 ; the keyboard ; If we're here, the keyboard sent a message MT_startDischarge: sbi DDRB, 2 ; Discharge through analog comp cbi PORTB,2 ldi Temp,25 OSSetTimeout Temp ; Wait 25 ms OSSetEntryPt MT_startMeasure ; Next time we start, we want to pick OSReturn 0 ; up at the start measurement point MT_startMeasure: cbi DDRB, 2 ; Make pin 2 an input again clr Temp out TCNT1H, Temp ; Clear timer 1 out TCNT1L, Temp sbi PORTB, 0 ; Raise Vcc to start charging ldi Temp, TCCR1BVal ; Start the timer waiting for charge out TCCR1B, Temp OSSetMessMask exp2(CapISR) ; Now we wait on the completion of charging clr Temp OSSetTimeout Temp OSSetEntryPt MT_finishMeasure ; Next time we start, we will be at OSReturn 0 ; the measurement handling code ;If we're here, the correct value is in the capture register MT_finishMeasure: OSGetMessageSrc Temp ; Get the list of who sent us messages andi Temp, exp2(capISR) ; If the capture ISR did not send it brne MT_fM1 OSReturn 1 ; something's wrong, so return bad error code MT_fM1: clr Temp out TCCR1B, Temp ; Shut off timer 1 cbi PORTB, 0 ; Drop Vcc to discharge capacitor in Temp, ICR1L ; Grab the capacitance value OSSendMess Temp, DisplayTask ; Send the value off to be displayed OSSetMessMask exp2(KbdTask) ; Wait for the next key press OSSetEntryPt MeasureTaskF ; Start from the beginning next time OSReturn 0 ; Done DisplayTaskF: ; If we're here, there's a capacitance to print ldi ZL, low(capMessage*2) ; Point to the first character ldi ZH, high(capMessage*2) ; of the output string ldi Temp, 26 sts OSBase+OSUARTCharCnt, Temp ; Tell the UART to 26 characters ldi YL, low(USRBase) ; Point at the beginning of memory ldi YH, high(USRBase) DT_0: ; Copy from program memory to SRAM lpm adiw ZL,1 st Y+,r0 dec Temp brne DT_0 ; Aim Z at the output string ldi ZL, low(USRBase) ldi ZH, high(USRBase) lds Temp, OSBase+OSStatus cbr Temp, exp2(txdone) ; Clear the bit indicating txdone sts OSBase+OSStatus, Temp ld Temp, Z+ ; Put the first character in Temp OSUARTWait Temp ; Send the message ; Now send the capacitance value itself OSGetMess Capacit, MeasureTask ; Format the string ldi ZL, low(USRBase) ldi ZH, high(USRBase) clr Temp DT_1: cpi Capacit, 100 brlo DT_tens subi Capacit, 100 inc Temp rjmp DT_1 DT_tens: subi Temp, -ascii0 st Z+, Temp clr Temp DT_2: cpi Capacit, 10 brlo DT_ones subi Capacit, 10 inc Temp rjmp DT_2 DT_ones: subi Temp, -ascii0 st Z+, Temp subi Capacit, -ascii0 st Z+, Capacit ldi Temp, 0x0d ; Newline character st Z, Temp ; We've done the conversion, now send the value ldi ZH, high(USRBase) ldi ZL, low(USRBase) ldi Temp, 4 sts OSBase+OSUARTCharCnt, Temp ; Tell the UART to 3 characters ld Temp, Z+ ; Put the first character in Temp OSUARTWait Temp OSReturn 0 ; Analog comparator capture complete ; Capacitance in nF is in capture low register T1CapISR: push Temp push Capacit in Temp, SREG push Temp ISRSendMess Temp, measureTask, CapISR ; Send a message to the measurement ; task signalling the available value pop Temp out SREG, Temp pop Capacit pop Temp reti