This code is from project: IR remote emulator with attiny45
USI_TWI_Slave.h
// This file has been prepared for Doxygen automatic documentation generation. /*! \file ******************************************************************** * * Atmel Corporation * * File : USI_TWI_Slave.h * Compiler : IAR EWAAVR 4.11A * Revision : $Revision: 1.14 $ * Date : $Date: Friday, December 09, 2005 17:25:38 UTC $ * Updated by : $Author: jtyssoe $ * * Support mail : avr@atmel.com * * Supported devices : All device with USI module can be used. * The example is written for the ATmega169, ATtiny26 & ATtiny2313 * * AppNote : AVR312 - Using the USI module as a TWI slave * * Description : Header file for USI_TWI driver * * * ****************************************************************************/ #include <avr/io.h> // HC-ADDED #include <avr/interrupt.h> // HC-ADDED //! Prototypes void USI_TWI_Slave_Initialise( unsigned char ); void USI_TWI_Transmit_Byte( unsigned char ); unsigned char USI_TWI_Receive_Byte( void ); unsigned char USI_TWI_Data_In_Receive_Buffer( void ); void Timer_Init(void); #define TRUE 1 #define FALSE 0 typedef unsigned char uint8_t; ////////////////////////////////////////////////////////////////// ///////////////// Driver Buffer Definitions ////////////////////// ////////////////////////////////////////////////////////////////// // 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes #define TWI_RX_BUFFER_SIZE (16) #define TWI_RX_BUFFER_MASK ( TWI_RX_BUFFER_SIZE - 1 ) #if ( TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK ) #error TWI RX buffer size is not a power of 2 #endif // 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes #define TWI_TX_BUFFER_SIZE (16) #define TWI_TX_BUFFER_MASK ( TWI_TX_BUFFER_SIZE - 1 ) #if ( TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK ) #error TWI TX buffer size is not a power of 2 #endif #define USI_SLAVE_CHECK_ADDRESS (0x00) #define USI_SLAVE_SEND_DATA (0x01) #define USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA (0x02) #define USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA (0x03) #define USI_SLAVE_REQUEST_DATA (0x04) #define USI_SLAVE_GET_DATA_AND_SEND_ACK (0x05) //! Device dependent defines #if defined(__AT90tiny26__) | defined(__ATtiny26__) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB #define PORT_USI_SDA PORTB0 #define PORT_USI_SCL PORTB2 #define PIN_USI_SDA PINB0 #define PIN_USI_SCL PINB2 #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_STRT_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect #endif #if defined(__AT90Tiny2313__) | defined(__ATtiny2313__) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB #define PORT_USI_SDA PORTB5 #define PORT_USI_SCL PORTB7 #define PIN_USI_SDA PINB5 #define PIN_USI_SCL PINB7 #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_STRT_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect #endif #if defined(__ATtiny25__) | defined(__ATtiny45__) | defined(__ATtiny85__) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB #define PORT_USI_SDA PORTB0 #define PORT_USI_SCL PORTB2 #define PIN_USI_SDA PINB0 #define PIN_USI_SCL PINB2 // #define USI_START_COND_INT USICIF #define USI_START_COND_INT USISIF // HC-CHANGED #define USI_START_VECTOR USI_START_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect #endif #if defined(__AT90Mega165__) | defined(__ATmega165__) | \ defined(__ATmega325__) | defined(__ATmega3250__) | \ defined(__ATmega645__) | defined(__ATmega6450__) | \ defined(__ATmega329__) | defined(__ATmega3290__) | \ defined(__ATmega649__) | defined(__ATmega6490__) #define DDR_USI DDRE #define PORT_USI PORTE #define PIN_USI PINE #define PORT_USI_SDA PORTE5 #define PORT_USI_SCL PORTE4 #define PIN_USI_SDA PINE5 #define PIN_USI_SCL PINE4 #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_START_vect #define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect #endif #if defined(__AT90Mega169__) | defined(__ATmega169__) #define DDR_USI DDRE #define PORT_USI PORTE #define PIN_USI PINE #define PORT_USI_SDA PORTE5 #define PORT_USI_SCL PORTE4 #define PIN_USI_SDA PINE5 #define PIN_USI_SCL PINE4 #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_STRT_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect #endif //! Functions implemented as macros #define SET_USI_TO_SEND_ACK() \ { \ USIDR = 0; /* Prepare ACK */ \ DDR_USI |= (1<<PORT_USI_SDA); /* Set SDA as output */ \ USISR = (0<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| /* Clear all flags, except Start Cond */ \ (0x0E<<USICNT0); /* set USI counter to shift 1 bit. */ \ } #define SET_USI_TO_READ_ACK() \ { \ DDR_USI &= ~(1<<PORT_USI_SDA); /* Set SDA as intput */ \ USIDR = 0; /* Prepare ACK */ \ USISR = (0<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| /* Clear all flags, except Start Cond */ \ (0x0E<<USICNT0); /* set USI counter to shift 1 bit. */ \ } #define SET_USI_TO_TWI_START_CONDITION_MODE() \ { \ USICR = (1<<USISIE)|(0<<USIOIE)| /* Enable Start Condition Interrupt. Disable Overflow Interrupt.*/ \ (1<<USIWM1)|(0<<USIWM0)| /* Set USI in Two-wire mode. No USI Counter overflow hold. */ \ (1<<USICS1)|(0<<USICS0)|(0<<USICLK)| /* Shift Register Clock Source = External, positive edge */ \ (0<<USITC); \ USISR = (0<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| /* Clear all flags, except Start Cond */ \ (0x0<<USICNT0); \ } #define SET_USI_TO_SEND_DATA() \ { \ DDR_USI |= (1<<PORT_USI_SDA); /* Set SDA as output */ \ USISR = (0<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| /* Clear all flags, except Start Cond */ \ (0x0<<USICNT0); /* set USI to shift out 8 bits */ \ } #define SET_USI_TO_READ_DATA() \ { \ DDR_USI &= ~(1<<PORT_USI_SDA); /* Set SDA as input */ \ USISR = (0<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| /* Clear all flags, except Start Cond */ \ (0x0<<USICNT0); /* set USI to shift out 8 bits */ \ }
USI_TWI_Slave.c
// This file has been prepared for Doxygen automatic documentation generation. /*! \file ******************************************************************** * * Atmel Corporation * * File : USI_TWI_Slave.c * Compiler : IAR EWAAVR 4.11A * Revision : $Revision: 1.14 $ * Date : $Date: Friday, December 09, 2005 17:25:38 UTC $ * Updated by : $Author: jtyssoe $ * * Support mail : avr@atmel.com * * Supported devices : All device with USI module can be used. * * AppNote : AVR312 - Using the USI module as a I2C slave * * Description : Functions for USI_TWI_receiver and USI_TWI_transmitter. * * ****************************************************************************/ // #include <ioavr.h> // HC-REMOVED // #include <inavr.h> // HC-REMOVED #include "USI_TWI_Slave.h" /*! Static Variables */ static unsigned char TWI_slaveAddress; static volatile unsigned char USI_TWI_Overflow_State; /*! Local variables */ static uint8_t TWI_RxBuf[TWI_RX_BUFFER_SIZE]; static volatile uint8_t TWI_RxHead; static volatile uint8_t TWI_RxTail; static uint8_t TWI_TxBuf[TWI_TX_BUFFER_SIZE]; static volatile uint8_t TWI_TxHead; static volatile uint8_t TWI_TxTail; /*! \brief Flushes the TWI buffers */ void Flush_TWI_Buffers(void) { TWI_RxTail = 0; TWI_RxHead = 0; TWI_TxTail = 0; TWI_TxHead = 0; } //********** USI_TWI functions **********// /*! \brief * Initialise USI for TWI Slave mode. */ void USI_TWI_Slave_Initialise( unsigned char TWI_ownAddress ) { Flush_TWI_Buffers(); TWI_slaveAddress = TWI_ownAddress; PORT_USI |= (1<<PORT_USI_SCL); // Set SCL high PORT_USI |= (1<<PORT_USI_SDA); // Set SDA high DDR_USI |= (1<<PORT_USI_SCL); // Set SCL as output DDR_USI &= ~(1<<PORT_USI_SDA); // Set SDA as input USICR = (1<<USISIE)|(0<<USIOIE)| // Enable Start Condition Interrupt. Disable Overflow Interrupt. (1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode. No USI Counter overflow prior // to first Start Condition (potentail failure) (1<<USICS1)|(0<<USICS0)|(0<<USICLK)| // Shift Register Clock Source = External, positive edge (0<<USITC); USISR = 0xF0; // Clear all flags and reset overflow counter } /*! \brief Puts data in the transmission buffer, Waits if buffer is full. */ void USI_TWI_Transmit_Byte( unsigned char data ) { unsigned char tmphead; tmphead = ( TWI_TxHead + 1 ) & TWI_TX_BUFFER_MASK; // Calculate buffer index. while ( tmphead == TWI_TxTail ); // Wait for free space in buffer. TWI_TxBuf[tmphead] = data; // Store data in buffer. TWI_TxHead = tmphead; // Store new index. } /*! \brief Returns a byte from the receive buffer. Waits if buffer is empty. */ unsigned char USI_TWI_Receive_Byte( void ) { unsigned char tmptail; unsigned char tmpRxTail; // Temporary variable to store volatile tmpRxTail = TWI_RxTail; // Not necessary, but prevents warnings while ( TWI_RxHead == tmpRxTail ); tmptail = ( TWI_RxTail + 1 ) & TWI_RX_BUFFER_MASK; // Calculate buffer index TWI_RxTail = tmptail; // Store new index return TWI_RxBuf[tmptail]; // Return data from the buffer. } /*! \brief Check if there is data in the receive buffer. */ unsigned char USI_TWI_Data_In_Receive_Buffer( void ) { unsigned char tmpRxTail; // Temporary variable to store volatile tmpRxTail = TWI_RxTail; // Not necessary, but prevents warnings return ( TWI_RxHead != tmpRxTail ); // Return 0 (FALSE) if the receive buffer is empty. } /*! \brief Usi start condition ISR * Detects the USI_TWI Start Condition and intialises the USI * for reception of the "TWI Address" packet. */ // HC-REMOVED // #pragma vector=USI_START_VECTOR // __interrupt void USI_Start_Condition_ISR(void) SIGNAL(SIG_USI_START) { unsigned char tmpUSISR; // Temporary variable to store volatile tmpUSISR = USISR; // Not necessary, but prevents warnings // Set default starting conditions for new TWI package USI_TWI_Overflow_State = USI_SLAVE_CHECK_ADDRESS; DDR_USI &= ~(1<<PORT_USI_SDA); // Set SDA as input while ( (PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF)) ); // Wait for SCL to go low to ensure the "Start Condition" has completed. // If a Stop condition arises then leave the interrupt to prevent waiting forever. USICR = (1<<USISIE)|(1<<USIOIE)| // Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART) (1<<USIWM1)|(1<<USIWM0)| // Set USI in Two-wire mode. (1<<USICS1)|(0<<USICS0)|(0<<USICLK)| // Shift Register Clock Source = External, positive edge (0<<USITC); USISR = (1<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| // Clear flags (0x0<<USICNT0); // Set USI to sample 8 bits i.e. count 16 external pin toggles. } /*! \brief USI counter overflow ISR * Handels all the comunication. Is disabled only when waiting * for new Start Condition. */ // HC-REMOVED // #pragma vector=USI_OVERFLOW_VECTOR // __interrupt void USI_Counter_Overflow_ISR(void) SIGNAL(SIG_USI_OVERFLOW) { unsigned char tmpTxTail; // Temporary variables to store volatiles unsigned char tmpUSIDR; switch (USI_TWI_Overflow_State) { // ---------- Address mode ---------- // Check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, else reset USI. case USI_SLAVE_CHECK_ADDRESS: if ((USIDR == 0) || (( USIDR>>1 ) == TWI_slaveAddress)) { if ( USIDR & 0x01 ) USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA; else { USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; SET_USI_TO_SEND_ACK(); } } else { SET_USI_TO_TWI_START_CONDITION_MODE(); } break; // ----- Master write data mode ------ // Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI. case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA: if ( USIDR ) // If NACK, the master does not want more data. { SET_USI_TO_TWI_START_CONDITION_MODE(); return; } // From here we just drop straight into USI_SLAVE_SEND_DATA if the master sent an ACK // Copy data from buffer to USIDR and set USI to shift byte. Next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA case USI_SLAVE_SEND_DATA: // Get data from Buffer tmpTxTail = TWI_TxTail; // Not necessary, but prevents warnings if ( TWI_TxHead != tmpTxTail ) { TWI_TxTail = ( TWI_TxTail + 1 ) & TWI_TX_BUFFER_MASK; USIDR = TWI_TxBuf[TWI_TxTail]; } else // If the buffer is empty then: { SET_USI_TO_TWI_START_CONDITION_MODE(); return; } USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA; SET_USI_TO_SEND_DATA(); break; // Set USI to sample reply from master. Next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA: USI_TWI_Overflow_State = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA; SET_USI_TO_READ_ACK(); break; // ----- Master read data mode ------ // Set USI to sample data from master. Next USI_SLAVE_GET_DATA_AND_SEND_ACK. case USI_SLAVE_REQUEST_DATA: USI_TWI_Overflow_State = USI_SLAVE_GET_DATA_AND_SEND_ACK; SET_USI_TO_READ_DATA(); break; // Copy data from USIDR and send ACK. Next USI_SLAVE_REQUEST_DATA case USI_SLAVE_GET_DATA_AND_SEND_ACK: // Put data into Buffer tmpUSIDR = USIDR; // Not necessary, but prevents warnings TWI_RxHead = ( TWI_RxHead + 1 ) & TWI_RX_BUFFER_MASK; TWI_RxBuf[TWI_RxHead] = tmpUSIDR; USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; SET_USI_TO_SEND_ACK(); break; } }
delay.h
#ifndef _H_DELAY_ #define _H_DELAY_ #define nop() __asm__ __volatile__("nop") void delay_ms(unsigned short ms); void delay_us(unsigned short us); #endif
delay.c
#include "main.h" #include <util/delay.h> #include "delay.h" /****************************************************************************/ /* It is better to put a delay in the loop than provide high value to */ /* standard function, because the code will be smaller, */ /****************************************************************************/ void delay_ms(unsigned short ms) { while ( ms ) { ms--; _delay_ms(1); } } void delay_us(unsigned short us) { while ( us ) { us--; _delay_us(1); } }
main.h
#ifndef _H_MAIN_H #define _H_MAIN_H // define CPU speed #define F_CPU 8000000L // some usefeuul macros #define H(a,b) a |=(1<<(b)) #define L(a,b) a &=~(1<<(b)) #define IS(a,b) bit_is_set(a,b) #define BS(a,b) (a & (1<<(b))) #endif
main.c
#include "main.h" #include <avr/io.h> #include <avr/interrupt.h> #include "delay.h" #include "USI_TWI_Slave.h" // command array size #define COMM_COUNT 18 // init data with device code const unsigned char init[] = { 0b11111111, 0b11111111, 0b00000000, 0b10101010, 0b00100010, 0b00100010, 0b10001000, 0b10001010, 0b10101000 }; // commands const unsigned char on[] = { 0b10001000, 0b10001000, 0b10101010, 0b10101010, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char mute[] = { 0b10101000, 0b10001000, 0b10101000, 0b10001000, 0b10101010, 0b00100010, 0b10000000 }; const unsigned char volUp[] = { 0b10100010, 0b00100010, 0b00101010, 0b10001010, 0b10101000, 0b10001000, 0b10000000 }; const unsigned char volDown[] = { 0b10001000, 0b10001000, 0b10001010, 0b10101010, 0b10101000, 0b10001000, 0b10000000 }; const unsigned char play[] = { 0b10100010, 0b10101010, 0b10100010, 0b10001000, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char next[] = { 0b10001000, 0b10101010, 0b10101010, 0b10001000, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char prev[] = { 0b10101000, 0b10101010, 0b10100010, 0b00101000, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char stop[] = { 0b10001010, 0b10101010, 0b10101000, 0b10001000, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char portable[] = { 0b10001000, 0b10001000, 0b10001010, 0b00100010, 0b10101010, 0b10001010, 0b10000000 }; const unsigned char cd[] = { 0b10100010, 0b10001010, 0b10001010, 0b00101000, 0b10100010, 0b00101000, 0b10000000 }; const unsigned char tuner[] = { 0b10001000, 0b10100010, 0b10100010, 0b10101000, 0b10100010, 0b00101000, 0b10000000 }; const unsigned char usb[] = { 0b10001010, 0b10001010, 0b00101010, 0b10001000, 0b10100010, 0b10001000, 0b10000000 }; const unsigned char pre_left[] = { 0b10101000, 0b10001000, 0b10101010, 0b00100010, 0b10101000, 0b10001000, 0b10000000 }; const unsigned char pre_right[] = { 0b10001000, 0b10100010, 0b00101010, 0b10101000, 0b10101000, 0b10001000, 0b10000000 }; const unsigned char fldr_up[] = { 0b10001000, 0b10001010, 0b10001010, 0b10101010, 0b00100010, 0b10001000, 0b10000000 }; const unsigned char fldr_down[] = { 0b10101010, 0b00101000, 0b10101000, 0b10001000, 0b10100010, 0b10001000, 0b10000000 }; const unsigned char shuffle[] = { 0b10001000, 0b10001010, 0b10101010, 0b10101000, 0b10001000, 0b10001000, 0b10000000 }; const unsigned char repeat[] = { 0b10101000, 0b10001010, 0b10101000, 0b10001010, 0b10001000, 0b10001000, 0b10000000 }; // commands array // commands received by I2C are indexes from this table const unsigned char *cmd_arr[COMM_COUNT] = { mute, volUp, volDown, on, play, next, prev, stop, portable, cd, usb, tuner, pre_left, pre_right, fldr_up, fldr_down, shuffle, repeat }; /****************************************************************************/ /* This function enables/disables interrupt generating ~36-38kHz square */ /* wave on pin PB1. On/Off sequence is from byte (function parameter). */ /****************************************************************************/ void sendOneByte(const unsigned char *byte) { unsigned char e = 7; do { if ( (*byte & (1<<e)) == (1<<e) ) { H(TIMSK, TOIE0); } else { L(TIMSK, TOIE0); L(PORTB, PB1); } // delay_us(410); delay_us(300); // time on my attiny45 runs slower, maybe // I have broken crystal resonator, I don't know // normally there should be 400-410 us } while(e--); } /****************************************************************************/ /* Function generate init sequence from init array. */ /****************************************************************************/ void initSequence() { unsigned char i = 0; for(i=0; i < 9; i++) sendOneByte(&init[i]); } /****************************************************************************/ /* Function sends IR command to device. */ /****************************************************************************/ void command(const unsigned char *comm) { unsigned char i = 0; initSequence(); for(i=0; i < 7; i++) sendOneByte(&comm[i]); } /****************************************************************************/ /* On every SIG_OVERFLOW0 there is a change on pin PB1. This generates */ /* 36-38kHz square wave. */ /****************************************************************************/ SIGNAL(SIG_OVERFLOW0) { TCNT0 = 0xAC; PORTB^=(1<<PB1); return; } /****************************************************************************/ /* This is the main loop, it's not complicated, because we work on */ /* interrupts. */ /****************************************************************************/ int main() { unsigned char byte; // set device I2C address to 0x10 USI_TWI_Slave_Initialise(0x10); // configure out pin for driving IR diode H(DDRB, PB1); L(PORTB, PB1); // configure timer L(TCCR0A, COM0A0); L(TCCR0A, COM0A1); H(TCCR0A, WGM01); H(TCCR0B, CS00); TCNT0 = 0xAC; // enable interrupts sei(); while(1) { // something was received if( USI_TWI_Data_In_Receive_Buffer() ) { // get command code byte = USI_TWI_Receive_Byte(); // check range (unsigned byte always > 0) if (byte < COMM_COUNT) command(cmd_arr[byte]); // send IR command } } }
Makefile
CPU=attiny45 GCC=avr-gcc CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min INCLUDES= LIBS= OBJCPY=avr-objcopy OBJECTS=main.o delay.o USI_TWI_Slave.o PROJECT_NAME=infrared HEX_FILE=$(PROJECT_NAME).hex HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex # this line shoud be replaced by your programmator # I use simplest ISP by parallel port and bunch of # wires and resistors. PROG=uisp PROG_FLAGS=-dprog=dapa -dpart=attiny26 all: cls $(PROJECT_NAME) obj size #upload $(PROJECT_NAME): $(OBJECTS) $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES) main.o: main.c main.h $(GCC) $(CFLAGS) $(INCLUDES) -c main.c delay.o: delay.c delay.h $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c USI_TWI_Slave.o: USI_TWI_Slave.c USI_TWI_Slave.h $(GCC) $(CFLAGS) $(INCLUDES) -c USI_TWI_Slave.c -D__ATtiny45__ obj: $(OBJECTS) $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE) clean: rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE) cls: clear size: du -b $(HEX_FILE) upload: all $(HEX_FILE) $(PROG) $(PROG_FLAGS) --erase --upload if=$(HEX_FILE) download: $(PROG) $(PROG_FLAGS) --download of=$(HEX_FILE_DUMP)
No comments:
Post a Comment