- 1. ATMEGA88PA: UART0, SPI
- 2. ATTINY261: PWM, USI (Universal Serial Interface) configured as SPI
PC ---(UART)---> ATMEGA88PA ---(SPI)---> ATTINY261 -------> PWM
Assembly Draft Code for ATMEGA88PA:
.include "m88padef.inc"
; Setup MCU to receive data at 2400 baud rate on the UART0
; -------- Register map (START) ----------
; R10 (KEY A) = Address of the I2C Slave (Read/~Write bit included) --> Address byte will be preceeded by 0xAA
; R3 (KEY M) = Byte RG_ADD1_HIGH
; R4 (KEY N) = Byte RG_ADD1_LOW
; R5 (KEY O) = Byte DATA1_HIGH
; R6 (KEY P) = Byte DATA1_LOW
; R22 = Flag for the jump instructions indicating if the next byte is a separator or a data byte (only the bit counts, if last bit == 0, current is a separator byte; if last bit == 1, current byte is a data byte)
; R23 = Dispatch for the loading of the registers R10, R3, R4, R5, and R6
; R18 = Timer0 prescalar
; R19 = Fast PWM R11 or R12 register load indicator (R11 < R12; and R11 + R12 = Total Base frequency counter)
; R11 = Fast PWM pulse width counter
; R12 = Fast PWM base frequency counter
; -------- Register map (END) ------------
.CSEG
.ORG 0x0000
RJMP RESET;
.ORG OC0Aaddr
RJMP OC0Aaddr_ISR;
.ORG OC0Baddr
RJMP OC0Baddr_ISR;
.ORG URXCaddr
RJMP URXCaddr_Rx_Complete_ISR;
.EQU I2C_SLAVE_ADDR_WRITE = 0x0A;
.EQU I2C_STAT_START_SENT = 0x08;
.EQU I2C_STAT_ADDRESS_SENT_ACK_RCVD = 0x18;
.EQU I2C_STAT_DATA_SENT_ACK_RCVD = 0x28;
; Separator bytes
.EQU SEPARATOR_ADDRESS = 0xAA;
.EQU SEPARATOR_RG_ADD1_HIGH = 0x4D;
.EQU SEPARATOR_RG_ADD1_LOW = 0x4E;
.EQU SEPARATOR_DATA1_HIGH = 0x4F;
.EQU SEPARATOR_DATA1_LOW = 0x50;
.EQU SEPARATOR_PWM_BASE_FREQ = 0x51;
.EQU SEPARATOR_PWM_PULSE_WIDTH = 0x52;
.EQU SEPARATOR_SIGNAL_SEND = 0x53;
RESET:
; ----- Set the stack pointer (START) ------
LDI R16, LOW(RAMEND);
LDI R17, HIGH(RAMEND);
OUT SPH, R17;
OUT SPL, R16;
; ----- Set the stack pointer (END) --------
; ------ Setup input and output ports (START) -------
; Set portC as output
SER R16;
OUT DDRC, R16;
; Set all the leds to the zero connected to portC
SER R16;
OUT PORTC, R16;
; Set portB as output
SER R16;
OUT DDRB, R16;
; Set all the leds to the zero connected to portC
SER R16;
OUT PORTB, R16;
; Set portB5 as output for the PWM
CBI PORTB, PORTB5;
; ------ Setup input and output ports (END) ---------
; ------- Setup USART0 2400, 8-bit, 1 stop bit , No parity (START) ----------
; Set the baud rate to 2400 -> UBRR would be set to 520d = (0x0208)
LDI R17, 0x02;
LDI R16, 0x08;
STS UBRR0H, R17;
STS UBRR0L, R16;
; Set the character size to 8 bits, No polarity, and 1 stop bit in UCSR0C
LDI R16, (1<<UCSZ01)|(1<<UCSZ00)|(0<<UPM00)|(0<<UPM01)|(0<<USBS0);
STS UCSR0C, R16;
; Enable the receiver only (RXEN0) and also enable receive data complete interrupt (RXCIE0) in UCSR0B
LDI R16, (1<<RXEN0) | (1<<RXCIE0);
STS UCSR0B, R16;
; ------- Setup USART0 2400, 8-bit, 1 stop bit , No parity (END) ------------
; ----------- SETUP I2C BIT RATE GENERATOR (START) --------
; Set the SCL clock to 200 KHz With TWBR = 42d = 0x2A and Prescalar value set to 1
;LDI R16, 0x2A;
;STS TWBR, R16;
; Set the SCL clock to 38 KHz With TWBR = 255d = 0xFF and Prescalar value set to 1
;LDI R16, 0xFF;
;STS TWBR, R16;
; Set the SCL clock to 8 KHz With TWBR = 20d = 0x14 and Prescalar value set to 64
LDI R16, (1<<TWPS1)|(1<<TWPS0);
STS TWSR , R16;
LDI R16, 0x14;
STS TWBR, R16;
; ----------- SETUP I2C BIT RATE GENERATOR (END) ----------
; ----------- SETUP TIMER0 FOR PWM GENERATION (START) ------
; Load the related registers
CLR R19;
; Load base frequency counter
LDI R16, 0xB4;
MOV R12, R16;
; Load pulse width counter
LDI R16, 0x14;
MOV R11, R16;
; Initially load the OCR0A with the pulse width counter
OUT OCR0A, R11;
; Initially load the OCR0B with the base frequency counter
OUT OCR0B, R12;
; Enable output compare A interrupt
;LDI R16, (1<<OCIE0B)|(1<<OCIE0A);
;STS TIMSK0, R16;
; Load the prescalar and start the clock
;LDI R18, (0<<CS02)|(0<<CS01)|(1<<CS00);
;OUT TCCR0B, R18;
; ----------- SETUP TIMER0 FOR PWM GENERATION (END) --------
; ------------ Enable SPI Communication on PortB(START) ----
; Enable the pin functions
; PB5 (SCK) to output
SBI DDRB, 5;
; PB4 (MISO) to input
CBI DDRB, 4;
; PB3 (MOSI) to output
SBI DDRB, 3;
; PB2 (~SS) to output
SBI DDRB, 2;
; Drive the slave select to LOW ALWAYS, as if the connected slave is always selected
CBI PORTB, 2;
; Enable SPI as master in 0-0 mode, and set the clock prescalar to fscl/128
LDI R16, (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
OUT SPCR, R16;
; ------------ Enable SPI Communication on PortB(END) ------
; Enable global interrupt and go..
SEI;
; --------- Blink some leds (START) ---------
; Clear all the registers involved
CLR R10;
CLR R3;
CLR R4;
CLR R5;
CLR R6;
CLR R22;
CLR R23;
MAIN_LOOP1:
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
RJMP MAIN_LOOP1;
; --------- Blink some leds (END) -----------
RETI;
URXCaddr_Rx_Complete_ISR:
; Read the data from UDR0 into R16;
LDS R16, UDR0;
; ------ Process the data read on the serial port (START) --
MOV R7, R16;
OUT PORTC, R7; Dubugging the serial port
; Increment R22
INC R22;
; Turn off the LEDs if the parsing error occurred in the last byte
CLR R21; To flag the instant when the error occurred..
SER R20;
;;;;OUT PORTB, R20;
; If R22 & 0x01 == 0x01, current byte is a separator byte; if R22 & 0x01 == 0x00, current byte is data byte
SBRC R22, 0;
RJMP PROCESS_SEPARATOR_BYTE;
RJMP PROCESS_DATA_BYTE;
PROCESS_SEPARATOR_BYTE:
; CHECK which separator byte is received in R7;
; MOVE R7 into the temporary resister R24 and work from there
MOV R24, R7;
; Compare the data in R24 with all the SEPARATORs and set R23 appropriately
CPI R24, SEPARATOR_ADDRESS;
BREQ LOAD_SEPARATOR_ADDRESS;
CPI R24, SEPARATOR_RG_ADD1_HIGH;
BREQ LOAD_SEPARATOR_RG_ADD1_HIGH;
CPI R24, SEPARATOR_RG_ADD1_LOW;
BREQ LOAD_SEPARATOR_RG_ADD1_LOW;
CPI R24, SEPARATOR_DATA1_HIGH;
BREQ LOAD_SEPARATOR_DATA1_HIGH;
CPI R24, SEPARATOR_DATA1_LOW;
BREQ LOAD_SEPARATOR_DATA1_LOW;
CPI R24, SEPARATOR_PWM_BASE_FREQ;
BREQ LOAD_SEPARATOR_PWM_BASE_FREQ;
CPI R24, SEPARATOR_PWM_PULSE_WIDTH;
BREQ LOAD_SEPARATOR_PWM_PULSE_WIDTH;
CPI R24, SEPARATOR_SIGNAL_SEND;
BREQ LOAD_SEPARATOR_SIGNAL_SEND;
RJMP WRONG_SEPARATOR_RECEIVED;
LOAD_SEPARATOR_ADDRESS:
LDI R23, 0x01;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_RG_ADD1_HIGH:
LDI R23, 0x02;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_RG_ADD1_LOW:
LDI R23, 0x03;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_DATA1_HIGH:
LDI R23, 0x04;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_DATA1_LOW:
LDI R23, 0x05;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_PWM_BASE_FREQ:
LDI R23, 0x06;
; Send out SEPARATOR_PWM_BASE_FREQ to the SPI slave
LDI R16, SEPARATOR_PWM_BASE_FREQ;
OUT SPDR, R16;
; Wait for SPI Transmission complete
WAIT_SPI_TX_SEPARATOR_PWM_BASE_FREQ:
IN R16, SPSR;
SBRS R16, SPIF;
RJMP WAIT_SPI_TX_SEPARATOR_PWM_BASE_FREQ;
; Dummy read to clear SPIF flag in SPSR
IN R16, SPDR;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_PWM_PULSE_WIDTH:
LDI R23, 0x07;
; Send out SEPARATOR_PWM_PULSE_WIDTH to the SPI slave
LDI R16, SEPARATOR_PWM_PULSE_WIDTH;
OUT SPDR, R16;
; Wait for SPI Transmission complete
WAIT_SPI_TX_SEPARATOR_PWM_PULSE_WIDTH:
IN R16, SPSR;
SBRS R16, SPIF;
RJMP WAIT_SPI_TX_SEPARATOR_PWM_PULSE_WIDTH;
; Dummy read to clear SPIF flag in SPSR
IN R16, SPDR;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
WRONG_SEPARATOR_RECEIVED:
DEC R22;
CLR R23;
RJMP END_OF_PROCESS_SEPARATOR_BYTE;
LOAD_SEPARATOR_SIGNAL_SEND:
DEC R22;
CLR R23;
RJMP SEND_DATA_TO_I2C_SLAVE;
END_OF_PROCESS_SEPARATOR_BYTE:
RJMP Rx_Complete_ISR_End; ; end of level PROCESS_SEPARATOR_BYTE:
PROCESS_DATA_BYTE:
; Compare the data in R23 with all the possible combinations
; if R23 == 0x01; load data from R7 into R10; --> Address byte (ADB)
; if R23 == 0x02; load data from R7 into R3; --> Byte RG_ADD1_HIGH
; if R23 == 0x03; load data from R7 into R4; --> Byte RG_ADD1_LOW
; if R23 == 0x04; load data from R7 into R5; --> Byte DATA1_HIGH
; if R23 == 0x05; load data from R7 into R6; --> Byte DATA1_LOW
CPI R23, 0x01;
BREQ LOAD_R10_WITH_ADDRESS;
CPI R23, 0x02;
BREQ LOAD_R3_WITH_RG_ADD1_HIGH;
CPI R23, 0x03;
BREQ LOAD_R4_WITH_RG_ADD1_LOW;
CPI R23, 0x04;
BREQ LOAD_R5_WITH_DATA1_HIGH;
CPI R23, 0x05;
BREQ LOAD_R6_WITH_DATA1_LOW;
CPI R23, 0x06;
BREQ LOAD_R12_WITH_PWM_BASE_FREQ;
CPI R23, 0x07;
BREQ LOAD_R11_WITH_PWM_PULSE_WIDTH;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R10_WITH_ADDRESS:
MOV R10, R7;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R3_WITH_RG_ADD1_HIGH:
MOV R3, R7;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R4_WITH_RG_ADD1_LOW:
MOV R4, R7;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R5_WITH_DATA1_HIGH:
MOV R5, R7;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R6_WITH_DATA1_LOW:
MOV R6, R7;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R12_WITH_PWM_BASE_FREQ:
MOV R12, R7;
OUT OCR0B, R12;
; Send out PWM_BASE_FREQ (R12) to the SPI slave
OUT SPDR, R12;
; Wait for SPI Transmission complete
WAIT_SPI_TX_PWM_BASE_FREQ:
IN R16, SPSR;
SBRS R16, SPIF;
RJMP WAIT_SPI_TX_PWM_BASE_FREQ;
; Dummy read to clear SPIF flag in SPSR
IN R16, SPDR;
RJMP END_OF_PROCESS_DATA_BYTE;
LOAD_R11_WITH_PWM_PULSE_WIDTH:
MOV R11, R7;
OUT OCR0A, R11;
; Send out PWM_PULSE_WIDTH (R11) to the SPI slave
OUT SPDR, R11;
; Wait for SPI Transmission complete
WAIT_SPI_TX_PWM_PULSE_WIDTH:
IN R16, SPSR;
SBRS R16, SPIF;
RJMP WAIT_SPI_TX_PWM_PULSE_WIDTH;
; Dummy read to clear SPIF flag in SPSR
IN R16, SPDR;
RJMP END_OF_PROCESS_DATA_BYTE;
END_OF_PROCESS_DATA_BYTE:
RJMP Rx_Complete_ISR_End; ; end of level PROCESS_DATA_BYTE:
; ------ Process the data read on the serial port (END) ----
; ----------------- Send data from R3 (DB1), R4 (DB2), R5 (CB), and R6 (BB) to the I2C slave addressed by R10 (START) -----
SEND_DATA_TO_I2C_SLAVE:
; Load the I2C start condition into R16
LDI R16, (1<<TWEN)|(1<<TWSTA)|(1<<TWINT);
STS TWCR, R16;
; Wait for the START condition to be sent on the line
START_SENT_LOOP:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP START_SENT_LOOP;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_START_SENT;
BRNE I2C_ERROR_ADDRESS;
; Load the TWDR with SLA+R/W address from R10
MOV R16, R10;
STS TWDR, R16;
; Send out the address by clearing the TWINT bit in TWCR
LDI R16, (1<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Wait for the address ACK to be received from the slave
WAIT_SLAVE_ADDRESS_ACK:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP WAIT_SLAVE_ADDRESS_ACK;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_ADDRESS_SENT_ACK_RCVD;
BRNE I2C_ERROR_ADDRESS;
RJMP SEND_DATA_OK;
I2C_ERROR_ADDRESS:
; Disable the TWI interface and let go off the SCL line
LDI R16, (0<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Turn on Alternating LEDS to indicate I2C error
LDI R20, 0x50;
OR R20, R21;
COM R20;
OUT PORTB, R20;
RJMP Rx_Complete_ISR_End;
SEND_DATA_OK:
; ++++++++++++++++ SENDING R3 BYTE DB1 (START)
; Load the data into TWDR from R3
STS TWDR, R3;
; Send out the data by clearing the TWINT bit in TWCR
LDI R16, (1<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Wait for the data ACK to be received from the slave
WAIT_SLAVE_DATA_ACK_FOR_R3_DB1:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP WAIT_SLAVE_DATA_ACK_FOR_R3_DB1;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_DATA_SENT_ACK_RCVD;
BRNE I2C_ERROR;
; ++++++++++++++++ SENDING R3 BYTE DB1 (END)
; ++++++++++++++++ SENDING R4 BYTE DB2 (START)
; Load the data into TWDR from R4
STS TWDR, R4;
; Send out the data by clearing the TWINT bit in TWCR
LDI R16, (1<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Wait for the data ACK to be received from the slave
WAIT_SLAVE_DATA_ACK_FOR_R4_DB2:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP WAIT_SLAVE_DATA_ACK_FOR_R4_DB2;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_DATA_SENT_ACK_RCVD;
BRNE I2C_ERROR;
; ++++++++++++++++ SENDING R4 BYTE DB2 (END)
; ++++++++++++++++ SENDING R5 BYTE CB (START)
; Load the data into TWDR from R5
STS TWDR, R5;
; Send out the data by clearing the TWINT bit in TWCR
LDI R16, (1<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Wait for the data ACK to be received from the slave
WAIT_SLAVE_DATA_ACK_FOR_R5_CB:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP WAIT_SLAVE_DATA_ACK_FOR_R5_CB;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_DATA_SENT_ACK_RCVD;
BRNE I2C_ERROR;
; ++++++++++++++++ SENDING R5 BYTE CB (END)
; ++++++++++++++++ SENDING R6 BYTE BB (START)
; Load the data into TWDR from R6
STS TWDR, R6;
; Send out the data by clearing the TWINT bit in TWCR
LDI R16, (1<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Wait for the data ACK to be received from the slave
WAIT_SLAVE_DATA_ACK_FOR_R6_BB:
LDS R16, TWCR;
SBRS R16, TWINT;
RJMP WAIT_SLAVE_DATA_ACK_FOR_R6_BB;
INC R21;
; Read the status code
LDS R16, TWSR;
ANDI R16, 0xF8; Masking out the prescalar bits
CPI R16, I2C_STAT_DATA_SENT_ACK_RCVD;
BRNE I2C_ERROR;
; ++++++++++++++++ SENDING R6 BYTE BB (END)
; Send a stop condition on the line
LDI R16, (1<<TWEN)|(1<<TWINT)|(1<<TWSTO);
STS TWCR, R16;
RJMP Rx_Complete_ISR_End;
I2C_ERROR:
; Disable the TWI interface and let go off the SCL line
LDI R16, (0<<TWEN)|(1<<TWINT);
STS TWCR, R16;
; Turn on Alternating LEDS to indicate I2C error
LDI R20, 0x50;
OR R20, R21;
COM R20;
OUT PORTB, R20;
RJMP Rx_Complete_ISR_End;
; ----------------- Send data from R3 (DB1), R4 (DB2), R5 (CB), and R6 (BB) to the I2C slave addressed by R10 (END) -------
Rx_Complete_ISR_End:
RETI;
; For the pulse width counter
OC0Aaddr_ISR:
; Turn off the pulse on portB5
CBI PORTB, PORTB5;
RETI;
; For the base frequency counter
OC0Baddr_ISR:
; Stop the timer
CLR R16;
OUT TCCR0B, R16;
; Clear the timer
OUT TCNT0, R16;
; Turn on the pulse on portB5
SBI PORTB, PORTB5;
; Load the prescalar and start the Timer
LDI R18, (0<<CS02)|(0<<CS01)|(1<<CS00);
OUT TCCR0B, R18;
RETI;
;------------------------------ END OF FILE ---------------------
Draft Assembly Code for ATTINY261:
.include "tn261def.inc"
;++++++++++++++++++++++++++++++++++++++++++++
; I/O Assignments
; Swap the SPI default port operation from PortB to PortA using USIPP
; PA0 = Input, DI, MISO
; PA1 = Output, DO, MOSI
; PA2 = Input, SCK
; PORTB(PB3-PB0) AND PORTA(PA7-PA4) as the debug output
;
; -------- SPI MESSAGE DECODE (START) ------
; R20 = Last bit of R20 indicates the current received byte is a separator (if 1) or data (if 0)
; R21 = Indicates which register to load with (R11 or R12)
; -------- SPI MESSAGE DECODE (END) --------
;
; ------- PWM SETUP TIMER-1 (START) --------
; OCR1C = Base frequency (R12)
; OCR1A = Pulse width (R11)
; ------- PWM SETUP TIMER-1 (END) ----------
;++++++++++++++++++++++++++++++++++++++++++++
.CSEG
.ORG 0x0000
RJMP RESET;
.ORG USI_OVFaddr
RJMP USI_OVFaddr_ISR; indicates that a byte has been received over the SPI
.EQU SEPARATOR_PWM_BASE_FREQ = 0x51;
.EQU SEPARATOR_PWM_PULSE_WIDTH = 0x52;
RESET:
; Setup stack pointer
LDI R17, high(RAMEND);
LDI R16, low(RAMEND);
;OUT SPH, R17;
OUT SPL, R16;
;+++++++++++++ I/O setup (START) +++++++++++
; Setup PORTA PA2:PA0 for the SPI communication(PA2->I, PA1->O; PA0->I)
CLR R16;
OUT DDRA, R16;
SBI DDRA, 1;
; Setup PortB PB3-PB0 as the debug output
LDI R16, 0x0F;
OUT DDRB, R16;
; Setup PortB PA7-PA4 as the debug output
SBI DDRA, 7;
SBI DDRA, 6;
SBI DDRA, 5;
SBI DDRA, 4;
; Initally set all output ports to zeros
CBI PORTB, 0;
CBI PORTB, 1;
CBI PORTB, 2;
CBI PORTB, 3;
CBI PORTA, 4;
CBI PORTA, 5;
CBI PORTA, 6;
CBI PORTA, 7;
;+++++++++++++ I/O setup (END) +++++++++++++
; ++++++++++++ SETUP SPI USING USI FROM EXTERNAL CLOCK (START) ++++++++++++++
; Swap the SPI default port operation from PortB to PortA using USIPP
SBI USIPP, 0;
; Enable counter-overflow interrupt
;LDI R16, (1<<USIOIE)|(1<<USIWM0)|(1<<USICLK);
LDI R16, (1<<USIOIE)|(1<<USIWM0)|(1<<USICS1);
OUT USICR, R16;
; Clear the counter-overflow flag by writing 1 to USIOIF of USISR register
LDI R16, (1<<USIOIF);
OUT USISR, R16;
; ++++++++++++ SETUP SPI USING USI FROM EXTERNAL CLOCK (START) ++++++++++++++
; +++++++++++++++ TIMER1-PWM SETUP (START) ++++++++++++
; Enable PLL for the MCU
LDI R16, (1<<PLLE);
OUT PLLCSR, R16;
; Wait for PLL to lock (~100ms)
WAIT_FOR_PLL_LOCK:
IN R16, PLLCSR;
SBRS R16, PLOCK;
RJMP WAIT_FOR_PLL_LOCK;
; Set FAST-PWM mode; Clear OC1A(PB1) on compare match
LDI R16, (1<<COM1A0)|(1<<PWM1A);
OUT TCCR1A, R16;
; Set the base frequency OCR1C (R12) to the top value 0xFF
SER R16;
MOV R12, R16;
OUT OCR1C, R12;
; Set the base frequency OCR1A (R11) to the half of maximum 0x0F
LDI R16, 0x0F;
MOV R11, R16;
OUT OCR1A, R11;
; Start off TIMER-1 by setting the prescalar in TCCR1B
LDI R16, (1<<CS10); No prescaling-> Full Speed
OUT TCCR1B, R16;
; +++++++++++++++ TIMER1-PWM SETUP (END) ++++++++++++++
; ++++++++++++ SPI MESSAGE DECODER SETUP (START) +++++++
CLR R20;
; ++++++++++++ SPI MESSAGE DECODER SETUP (END) +++++++++
; Enable interrupts and go
SEI;
MASTER_LOOP1:
RJMP MASTER_LOOP1;
RET;
USI_OVFaddr_ISR: ; use R16 and R17 as the temporary registers
; Read the data from USIDR into R18;
IN R18, USIDR;
; Clear the counter-overflow flag by writing 1 to USIOIF of USISR register
LDI R17, (1<<USIOIF);
OUT USISR, R17;
; Process the rest of the data here
INC R20; Separator or data indicator; if the LSB is 1, received byte is a separator or data otherwise
MOV R16, R20;
ANDI R16, 0x01;
CPI R16, 0x00;
BREQ LOAD_DATA;
; Load Separator here and check which separator was received
MOV R16, R18;
CPI R16, SEPARATOR_PWM_BASE_FREQ;
BREQ LOAD_SEPARATOR_PWM_BASE_FREQ;
MOV R16, R18;
CPI R16, SEPARATOR_PWM_PULSE_WIDTH;
BREQ LOAD_SEPARATOR_PWM_PULSE_WIDTH;
; Wrong Separator received; try again
CLR R20;
CLR R21;
RJMP END_OF_USI_OVFaddr_ISR;
LOAD_SEPARATOR_PWM_BASE_FREQ:
LDI R21, 0x01; Load next byte into R12 for the base frequency (OCR1C)
RJMP END_OF_USI_OVFaddr_ISR;
LOAD_SEPARATOR_PWM_PULSE_WIDTH:
LDI R21, 0x02; Load next byte into R11 for the pulse width (OCR1A)
RJMP END_OF_USI_OVFaddr_ISR;
LOAD_DATA:
; Check with register to load
MOV R16, R21;
CPI R16, 0x01;
BREQ LOAD_BASE_FREQ_DATA_INTO_R12;
; Check with register to load
MOV R16, R21;
CPI R16, 0x02;
BREQ LOAD_PULSE_WIDTH_DATA_INTO_R11;
; Else if jump to end
RJMP END_OF_USI_OVFaddr_ISR;
LOAD_BASE_FREQ_DATA_INTO_R12:
MOV R12, R18;
RJMP END_OF_LOAD_DATA;
LOAD_PULSE_WIDTH_DATA_INTO_R11:
MOV R11, R18;
RJMP END_OF_LOAD_DATA;
END_OF_LOAD_DATA:
; Stop the PWM TIMER-1
CLR R16;
OUT TCCR1B, R16;
; Update the base frequency
OUT OCR1C, R12;
; Update the pulse width
OUT OCR1A, R11;
; Restart the TIMER-1
LDI R16, (1<<CS10);
OUT TCCR1B, R16;
RJMP END_OF_USI_OVFaddr_ISR;
END_OF_USI_OVFaddr_ISR:
; Debug Display upper 4 nibble at PORTA(PA7-PA4)
;MOV R18, R16;
;ANDI R18, 0xF0;
;OUT PORTA, R18;
RETI;
;-------------------------------- END OF FILE -------------------