diff --git a/LUFA/Drivers/Peripheral/XMEGA/SerialSPI_XMEGA.h b/LUFA/Drivers/Peripheral/XMEGA/SerialSPI_XMEGA.h index cb86a9900..34c704425 100644 --- a/LUFA/Drivers/Peripheral/XMEGA/SerialSPI_XMEGA.h +++ b/LUFA/Drivers/Peripheral/XMEGA/SerialSPI_XMEGA.h @@ -91,7 +91,7 @@ /* Private Interface - For use in library only: */ #if !defined(__DOXYGEN__) - #define SERIAL_SPI_UBBRVAL(Baud) ((Baud < (F_CPU / 2)) ? ((F_CPU / (2 * Baud)) - 1) : 0) + #define SERIAL_SPI_UBBRVAL(Baud) ((Baud < (F_CPU / 2)) ? ((F_CPU / (2ULL * Baud)) - 1) : 0) #endif /* Public Interface - May be used in end-application: */ diff --git a/LUFA/Drivers/USB/Core/XMEGA/Endpoint_XMEGA.h b/LUFA/Drivers/USB/Core/XMEGA/Endpoint_XMEGA.h index 990620eae..4a243b0d6 100644 --- a/LUFA/Drivers/USB/Core/XMEGA/Endpoint_XMEGA.h +++ b/LUFA/Drivers/USB/Core/XMEGA/Endpoint_XMEGA.h @@ -444,6 +444,19 @@ return (USB_Endpoint_SelectedEndpoint & ENDPOINT_DIR_IN); } + /** Sets the direction of the currently selected endpoint. + * + * \param[in] DirectionMask New endpoint direction, as a \c ENDPOINT_DIR_* mask. + */ + static inline void Endpoint_SetEndpointDirection(const uint8_t DirectionMask) ATTR_ALWAYS_INLINE; + static inline void Endpoint_SetEndpointDirection(const uint8_t DirectionMask) + { + //TODO: Needs to be completed! + (void) DirectionMask; +// UECFG0X = ((UECFG0X & ~(1 << EPDIR)) | (DirectionMask ? (1 << EPDIR) : 0)); + //USB_Endpoint_SelectedEndpoint = (USB_Endpoint_SelectedEndpoint & ~ENDPOINT_DIR_IN) | DirectionMask; + } + /** Reads one byte from the currently selected endpoint's bank, for OUT direction endpoints. * * \ingroup Group_EndpointPrimitiveRW_XMEGA diff --git a/Projects/AVRISP-MKII/AVRISP-MKII.c b/Projects/AVRISP-MKII/AVRISP-MKII.c index 4539619f6..62bc6b6aa 100644 --- a/Projects/AVRISP-MKII/AVRISP-MKII.c +++ b/Projects/AVRISP-MKII/AVRISP-MKII.c @@ -80,6 +80,15 @@ void SetupHardware(void) /* Disable clock division */ clock_prescale_set(clock_div_1); +#elif (ARCH == ARCH_XMEGA) + XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU); + XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL); + + // Start the 32MHz internal RC oscillator and start the DFLL to increase it to F_USB using the USB SOF as a reference + XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); + XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB); + PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; + sei(); #endif /* Hardware Initialization */ @@ -87,7 +96,7 @@ void SetupHardware(void) #if defined(RESET_TOGGLES_LIBUSB_COMPAT) UpdateCurrentCompatibilityMode(); #endif - + /* USB Stack Initialization */ USB_Init(); } @@ -113,7 +122,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) ConfigSuccess &= Endpoint_ConfigureEndpoint(AVRISP_DATA_OUT_EPADDR, EP_TYPE_BULK, AVRISP_DATA_EPSIZE, 1); /* Setup AVRISP Data IN endpoint if it is using a physically different endpoint */ +#if (ARCH != ARCH_XMEGA) if ((AVRISP_DATA_IN_EPADDR & ENDPOINT_EPNUM_MASK) != (AVRISP_DATA_OUT_EPADDR & ENDPOINT_EPNUM_MASK)) +#endif ConfigSuccess &= Endpoint_ConfigureEndpoint(AVRISP_DATA_IN_EPADDR, EP_TYPE_BULK, AVRISP_DATA_EPSIZE, 1); /* Indicate endpoint configuration success or failure */ diff --git a/Projects/AVRISP-MKII/Config/AppConfig.h b/Projects/AVRISP-MKII/Config/AppConfig.h index 245b6ab44..00c71bf70 100644 --- a/Projects/AVRISP-MKII/Config/AppConfig.h +++ b/Projects/AVRISP-MKII/Config/AppConfig.h @@ -42,27 +42,128 @@ #ifndef _APP_CONFIG_H_ #define _APP_CONFIG_H_ + #if (ARCH == ARCH_AVR8) + #define AUX_LINE_PORT PORTB + #define AUX_LINE_PIN PINB + #define AUX_LINE_DDR DDRB + #if (BOARD == BOARD_U2S) + #define AUX_LINE_MASK (1 << 0) + #else + #define AUX_LINE_MASK (1 << 4) + #endif + #define VTARGET_ADC_CHANNEL 2 + #define VTARGET_REF_VOLTS 5 + #define VTARGET_SCALE_FACTOR 1 + #define VTARGET_USE_INTERNAL_REF + #elif (ARCH == ARCH_XMEGA) +/* Wiring in default config (REMAP SPI Enable or USART SPI Master) + * PORTC + * PIN + * 0 O---120Ohm---| + * O-- RESET (PDI/ISP PIN5) + * 1 O---120Ohm---| + * + * 2 O---180Ohm---O + * | + * 3 O---180Ohm---O + * | + * 4 x O-- MISO/DAT (PDI/ISP PIN1) + * | + * 5 O---120Ohm---|-- SCK (PDI/ISP PIN5) + * | + * 6 O---120Ohm---O + * + * 7 O---120Ohm------ MOSI (PDI/ISP PIN4) + * + * + * GND O---------------O--------- GND (PDI/ISP PIN6) + * | + * PA0 O----O-1.5KOhm--O + * | Scale theoritical 7.66667 with this Resistors, but we needed to adjust to 8.43333. + * O--10KOhm--O You can read voltage from target + * ? Or you can supply the target. We prefer to have addional Power OUT Pins for supply the target. + * VCC O---------???---O---------- VCC (PDI/ISP PIN2) (Dangerous! But can be helpfull, you can also leave it open or use other options) + * + * This allows to program PDI/ISP but only 3.3V!!!!!! + */ + //Remaping spi will swap SCK and MOSI (Same pinout as USART in SPI master mode) + #define REMAP_SPI + + //Use USART interface in SPI master mode instead of the SPI module. + //Recommended it allows higher precision of the SPI CLK. + #define USART_SPI_MASTER - #define AUX_LINE_PORT PORTB - #define AUX_LINE_PIN PINB - #define AUX_LINE_DDR DDRB - #if (BOARD == BOARD_U2S) + #ifdef USART_SPI_MASTER + #define USART_SPI_REG USARTC1 + #else + #define SPI_REG SPIC + #endif + + #define SPI_PORT PORTC + + #if defined(REMAP_SPI) || defined(USART_SPI_MASTER) + #define SPI_SCK_MASK (1 << 5) + #define SPI_SCK_CTRL PIN5CTRL + + #define SPI_MOSI_MASK (1 << 7) + #define SPI_MOSI_CTRL PIN7CTRL + #else + #define SPI_SCK_MASK (1 << 7) + #define SPI_SCK_CTRL PIN7CTRL + + #define SPI_MOSI_MASK (1 << 5) + #define SPI_MOSI_CTRL PIN5CTRL + #endif + + #define SPI_MISO_MASK (1 << 6) + #define SPI_MISO_CTRL PIN6CTRL + + + + #define RESCUE_PORT PORTD + #define RESCUE_TIMER TCD0 + #define RESCUE_PIN_MASK (1 << 0) + #define RESCUE_TIMER_CMP_EN TC0_CCAEN_bm //A if pin 0, B if pin 1... + #define RESCUE_TIMER_CMP_REG CCA + + #define PDI_USART USARTC0 + #define PDI_PORT PORTC + #define PDI_RX_MASK (1 << 2) + #define PDI_RX_CTRL PIN2CTRL + + #define PDI_TX_MASK (1 << 3) + #define PDI_TX_CTRL PIN3CTRL + + #define PDI_XCK_MASK (1 << 1) + #define PDI_XCK_CTRL PIN1CTRL + + #define AUX_LINE_PORT PORTC #define AUX_LINE_MASK (1 << 0) - #else - #define AUX_LINE_MASK (1 << 4) - #endif + #define AUX_LINE_CTRL PIN0CTRL + + #define DELAY_TIMER TCC0 + #define DELAY_TIMER_OVF_vect TCC0_OVF_vect + #define SW_SPI_TIMER TCC1 + #define SW_SPI_TIMER_CCA_vect TCC1_CCA_vect + #define SW_SPI_TIMER_CCB_vect TCC1_CCB_vect + #define SW_SPI_TIMER_OVF_vect TCC1_OVF_vect + #define SW_SPI_PIN_IRQ_vect PORTC_INT0_vect + #define VTARGET_ADC_CHANNEL 1 //Hardcoded allways 1 Connected to PA1 + #define VTARGET_REF_VOLTS 1.00 //Hardcoded allways 1.00 + #define VTARGET_SCALE_FACTOR 6.8 //GND<->R1<-ADC->R2<->SIGNAL | SCALE = (R1+R2)/R1 + #endif #define ENABLE_ISP_PROTOCOL #define ENABLE_XPROG_PROTOCOL - #define VTARGET_ADC_CHANNEL 2 - #define VTARGET_REF_VOLTS 5 - #define VTARGET_SCALE_FACTOR 1 -// #define VTARGET_USE_INTERNAL_REF - #define NO_VTARGET_DETECT + + +// #define NO_VTARGET_DETECT // #define XCK_RESCUE_CLOCK_ENABLE // #define INVERTED_ISP_MISO +// #define LIBUSB_DRIVER_COMPAT +// #define RESET_TOGGLES_LIBUSB_COMPAT // #define FIRMWARE_VERSION_MINOR 0x11 #endif diff --git a/Projects/AVRISP-MKII/Config/LUFAConfig.h b/Projects/AVRISP-MKII/Config/LUFAConfig.h index 811d0fd8f..7d78ce343 100644 --- a/Projects/AVRISP-MKII/Config/LUFAConfig.h +++ b/Projects/AVRISP-MKII/Config/LUFAConfig.h @@ -85,6 +85,39 @@ // #define NO_AUTO_VBUS_MANAGEMENT // #define INVERTED_VBUS_ENABLE_LINE + #elif (ARCH == ARCH_XMEGA) + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + #define ORDERED_EP_CONFIG + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ + #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRIHIGH) +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT + #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ +// #define USE_RAM_DESCRIPTORS + #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS + #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 16 + #define DEVICE_STATE_AS_GPIOR 0 + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE + #define MAX_ENDPOINT_INDEX 4 + #define NO_DEVICE_REMOTE_WAKEUP + #define NO_DEVICE_SELF_POWER + #else #error Unsupported architecture for this LUFA configuration file. diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c index 2e93139fb..349d7bf0d 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c @@ -47,14 +47,26 @@ static volatile uint8_t ISPProtocol_ResponseTogglesRemaining; /** ISR to toggle MOSI pin when TIMER1 overflows */ +#if ARCH == ARCH_AVR8 ISR(TIMER1_OVF_vect, ISR_BLOCK) { PINB |= (1 << PB2); // toggle PB2 (MOSI) by writing 1 to its bit in PINB ISPProtocol_HalfCyclesRemaining--; } +#elif (ARCH == ARCH_XMEGA) +ISR(SW_SPI_TIMER_CCA_vect, ISR_BLOCK) +{ + SPI_PORT.OUTTGL = SPI_MOSI_MASK; + ISPProtocol_HalfCyclesRemaining--; +} +#endif /** ISR to listen for toggles on MISO pin */ +#if ARCH == ARCH_AVR8 ISR(PCINT0_vect, ISR_BLOCK) +#elif (ARCH == ARCH_XMEGA) +ISR(SW_SPI_PIN_IRQ_vect, ISR_BLOCK) +#endif { ISPProtocol_ResponseTogglesRemaining--; } @@ -420,6 +432,8 @@ void ISPProtocol_Calibrate(void) Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); + //TODO: Learn it and implement it... +#if (ARCH == ARCH_AVR8) /* Enable pull-up on MISO and release ~RESET */ DDRB = ~(1 << PB3); PORTB |= ( (1 << PB4) | (1 << PB3) ); @@ -455,7 +469,46 @@ void ISPProtocol_Calibrate(void) /* Check if device responded with a success message or if we timed out */ if (ISPProtocol_ResponseTogglesRemaining) ResponseStatus = STATUS_CMD_TOUT; +#elif (ARCH == ARCH_XMEGA) + //TODO: This needs to be tested + /* Enable pull-up on MISO and release ~RESET */ + SPI_PORT.SPI_MISO_CTRL = PORT_OPC_PULLUP_gc; + SPI_PORT.DIRCLR = SPI_MISO_MASK; + AUX_LINE_PORT.DIRCLR = AUX_LINE_MASK; + + /* Set up MISO pin (PCINT3) to listen for toggles */ + SPI_PORT.INT0MASK = SPI_MISO_MASK; + /* Set up timer that fires at a rate of 65536 Hz - this will drive the MOSI toggle */ + SW_SPI_TIMER.CCA = ISPPROTOCOL_CALIB_TICKS - 1; + SW_SPI_TIMER.PER = ISPPROTOCOL_CALIB_TICKS - 1; + SW_SPI_TIMER.CTRLB = TC_WGMODE_FRQ_gc; // set for fast PWM, TOP = OCR1A + SW_SPI_TIMER.CTRLA = TC_CLKSEL_DIV1_gc; // ... and no clock prescaling + SW_SPI_TIMER.CNT = 0; + + /* Initialize counter variables */ + ISPProtocol_HalfCyclesRemaining = ISPPROTOCOL_CALIB_HALF_CYCLE_LIMIT; + ISPProtocol_ResponseTogglesRemaining = ISPPROTOCOL_CALIB_SUCCESS_TOGGLE_NUM; + + /* Turn on interrupts */ + SW_SPI_TIMER.INTCTRLB = TC_CCAINTLVL_MED_gc; // enable interrupts for PCINT7:0 (don't touch setting for PCINT12:8) + SPI_PORT.INT0MASK |= PORT_INT0LVL_MED_gc; // enable T1 OVF interrupt (and no other T1 interrupts) + + /* Turn on global interrupts for the following block, restoring current state at end */ + NONATOMIC_BLOCK(NONATOMIC_RESTORESTATE) + { + /* Let device do its calibration, wait for response on MISO */ + while (ISPProtocol_HalfCyclesRemaining && ISPProtocol_ResponseTogglesRemaining); + + /* Disable timer and pin change interrupts */ + SW_SPI_TIMER.INTCTRLB &= ~TC_CCAINTLVL_MED_gc; + SPI_PORT.INT0MASK &= ~PORT_INT0LVL_gm; + } + + /* Check if device responded with a success message or if we timed out */ + if (ISPProtocol_ResponseTogglesRemaining) + ResponseStatus = STATUS_CMD_TOUT; +#endif /* Report back to PC via USB */ Endpoint_Write_8(CMD_OSCCAL); Endpoint_Write_8(ResponseStatus); diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.c b/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.c index b6f636932..19d5b3490 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.c +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.c @@ -41,68 +41,297 @@ * * \hideinitializer */ -static const uint8_t SPIMaskFromSCKDuration[] PROGMEM = -{ -#if (F_CPU == 8000000) - SPI_SPEED_FCPU_DIV_2, // AVRStudio = 8MHz SPI, Actual = 4MHz SPI - SPI_SPEED_FCPU_DIV_2, // AVRStudio = 4MHz SPI, Actual = 4MHz SPI - SPI_SPEED_FCPU_DIV_4, // AVRStudio = 2MHz SPI, Actual = 2MHz SPI - SPI_SPEED_FCPU_DIV_8, // AVRStudio = 1MHz SPI, Actual = 1MHz SPI - SPI_SPEED_FCPU_DIV_16, // AVRStudio = 500KHz SPI, Actual = 500KHz SPI - SPI_SPEED_FCPU_DIV_32, // AVRStudio = 250KHz SPI, Actual = 250KHz SPI - SPI_SPEED_FCPU_DIV_64, // AVRStudio = 125KHz SPI, Actual = 125KHz SPI -#elif (F_CPU == 16000000) - SPI_SPEED_FCPU_DIV_2, // AVRStudio = 8MHz SPI, Actual = 8MHz SPI - SPI_SPEED_FCPU_DIV_4, // AVRStudio = 4MHz SPI, Actual = 4MHz SPI - SPI_SPEED_FCPU_DIV_8, // AVRStudio = 2MHz SPI, Actual = 2MHz SPI - SPI_SPEED_FCPU_DIV_16, // AVRStudio = 1MHz SPI, Actual = 1MHz SPI - SPI_SPEED_FCPU_DIV_32, // AVRStudio = 500KHz SPI, Actual = 500KHz SPI - SPI_SPEED_FCPU_DIV_64, // AVRStudio = 250KHz SPI, Actual = 250KHz SPI - SPI_SPEED_FCPU_DIV_128 // AVRStudio = 125KHz SPI, Actual = 125KHz SPI -#else - #error No SPI prescaler masks for chosen F_CPU speed. +#if (ARCH == ARCH_XMEGA) + +typedef struct SPISetting_t { + uint8_t hardware_spi:1; + uint8_t prediv:7; + uint16_t value; +} SPISetting_t; + + #if defined(USART_SPI_MASTER) + /* Theoritical should we be able to go down until bsel will overflow + * but for some reasons lower frequencies generates random bit rates... + * (< 10000Hz) Maybe this is a problem with the user code, maybe it + * specified somewhere in the datasheet or it may be a hardware bug. + * It was even tested with static bsel that also results in wrong + * bitrates... + * But who cares software SPI works fine with this low rates. + */ + #define SPI_MIN_HW_FREQ() 20000 //(F_CPU/(2*(65535+1))+1) + #define SPI_GEN_HW_VALUE(freq) SERIAL_SPI_UBBRVAL(freq) + #else + /* Max prediv is 128 */ + #define SPI_MIN_HW_FREQ() (F_CPU/128) + #define SPI_GEN_HW_VALUE(freq) (freq >= (F_CPU/2)) ? SPI_SPEED_FCPU_DIV_2 : \ + (freq >= (F_CPU/4)) ? SPI_SPEED_FCPU_DIV_4 : \ + (freq >= (F_CPU/8)) ? SPI_SPEED_FCPU_DIV_8 : \ + (freq >= (F_CPU/16)) ? SPI_SPEED_FCPU_DIV_16 : \ + (freq >= (F_CPU/32)) ? SPI_SPEED_FCPU_DIV_32 : \ + (freq >= (F_CPU/64)) ? SPI_SPEED_FCPU_DIV_64 : \ + SPI_SPEED_FCPU_DIV_128 + #endif + + #define SPI_IS_HW_SPI(freq) (freq >= SPI_MIN_HW_FREQ()) + #define SPI_SW_PREDIV(freq) (ISP_TIMER_COMP(1,freq) >= 32767ULL) ? TC_CLKSEL_DIV64_gc : TC_CLKSEL_DIV1_gc + #define SPI_SW_VALUE(freq) (ISP_TIMER_COMP(1,freq) >= 32767ULL) ? ISP_TIMER_COMP(64, freq) : ISP_TIMER_COMP(1, freq) + #define SPI_GEN_SETTINGS_ROW(freq) { \ + SPI_IS_HW_SPI(freq) ? 1 : 0, \ + SPI_IS_HW_SPI(freq) ? 0 : SPI_SW_PREDIV(freq), \ + SPI_IS_HW_SPI(freq) ? SPI_GEN_HW_VALUE(freq) : SPI_SW_VALUE(freq) \ + } + static const struct SPISetting_t SPISettings[] PROGMEM = + { + SPI_GEN_SETTINGS_ROW(8000000), + SPI_GEN_SETTINGS_ROW(4000000), + SPI_GEN_SETTINGS_ROW(2000000), + SPI_GEN_SETTINGS_ROW(1000000), + SPI_GEN_SETTINGS_ROW(500000), + SPI_GEN_SETTINGS_ROW(250000), + SPI_GEN_SETTINGS_ROW(125000), + SPI_GEN_SETTINGS_ROW(96386), + SPI_GEN_SETTINGS_ROW(89888), + SPI_GEN_SETTINGS_ROW(84211), + SPI_GEN_SETTINGS_ROW(79208), + SPI_GEN_SETTINGS_ROW(74767), + SPI_GEN_SETTINGS_ROW(70797), + SPI_GEN_SETTINGS_ROW(67227), + SPI_GEN_SETTINGS_ROW(64000), + SPI_GEN_SETTINGS_ROW(61069), + SPI_GEN_SETTINGS_ROW(58395), + SPI_GEN_SETTINGS_ROW(55945), + SPI_GEN_SETTINGS_ROW(51613), + SPI_GEN_SETTINGS_ROW(49690), + SPI_GEN_SETTINGS_ROW(47905), + SPI_GEN_SETTINGS_ROW(46243), + SPI_GEN_SETTINGS_ROW(43244), + SPI_GEN_SETTINGS_ROW(41885), + SPI_GEN_SETTINGS_ROW(39409), + SPI_GEN_SETTINGS_ROW(38278), + SPI_GEN_SETTINGS_ROW(36200), + SPI_GEN_SETTINGS_ROW(34335), + SPI_GEN_SETTINGS_ROW(32654), + SPI_GEN_SETTINGS_ROW(31129), + SPI_GEN_SETTINGS_ROW(29740), + SPI_GEN_SETTINGS_ROW(28470), + SPI_GEN_SETTINGS_ROW(27304), + SPI_GEN_SETTINGS_ROW(25724), + SPI_GEN_SETTINGS_ROW(24768), + SPI_GEN_SETTINGS_ROW(23461), + SPI_GEN_SETTINGS_ROW(22285), + SPI_GEN_SETTINGS_ROW(21221), + SPI_GEN_SETTINGS_ROW(20254), + SPI_GEN_SETTINGS_ROW(19371), + SPI_GEN_SETTINGS_ROW(18562), + SPI_GEN_SETTINGS_ROW(17583), + SPI_GEN_SETTINGS_ROW(16914), + SPI_GEN_SETTINGS_ROW(16097), + SPI_GEN_SETTINGS_ROW(15356), + SPI_GEN_SETTINGS_ROW(14520), + SPI_GEN_SETTINGS_ROW(13914), + SPI_GEN_SETTINGS_ROW(13224), + SPI_GEN_SETTINGS_ROW(12599), + SPI_GEN_SETTINGS_ROW(12031), + SPI_GEN_SETTINGS_ROW(11511), + SPI_GEN_SETTINGS_ROW(10944), + SPI_GEN_SETTINGS_ROW(10431), + SPI_GEN_SETTINGS_ROW(9963), + SPI_GEN_SETTINGS_ROW(9468), + SPI_GEN_SETTINGS_ROW(9081), + SPI_GEN_SETTINGS_ROW(8612), + SPI_GEN_SETTINGS_ROW(8239), + SPI_GEN_SETTINGS_ROW(7851), + SPI_GEN_SETTINGS_ROW(7498), + SPI_GEN_SETTINGS_ROW(7137), + SPI_GEN_SETTINGS_ROW(6809), + SPI_GEN_SETTINGS_ROW(6478), + SPI_GEN_SETTINGS_ROW(6178), + SPI_GEN_SETTINGS_ROW(5879), + SPI_GEN_SETTINGS_ROW(5607), + SPI_GEN_SETTINGS_ROW(5359), + SPI_GEN_SETTINGS_ROW(5093), + SPI_GEN_SETTINGS_ROW(4870), + SPI_GEN_SETTINGS_ROW(4633), + SPI_GEN_SETTINGS_ROW(4418), + SPI_GEN_SETTINGS_ROW(4209), + SPI_GEN_SETTINGS_ROW(4019), + SPI_GEN_SETTINGS_ROW(3823), + SPI_GEN_SETTINGS_ROW(3645), + SPI_GEN_SETTINGS_ROW(3474), + SPI_GEN_SETTINGS_ROW(3310), + SPI_GEN_SETTINGS_ROW(3161), + SPI_GEN_SETTINGS_ROW(3011), + SPI_GEN_SETTINGS_ROW(2869), + SPI_GEN_SETTINGS_ROW(2734), + SPI_GEN_SETTINGS_ROW(2611), + SPI_GEN_SETTINGS_ROW(2484), + SPI_GEN_SETTINGS_ROW(2369), + SPI_GEN_SETTINGS_ROW(2257), + SPI_GEN_SETTINGS_ROW(2152), + SPI_GEN_SETTINGS_ROW(2052), + SPI_GEN_SETTINGS_ROW(1956), + SPI_GEN_SETTINGS_ROW(1866), + SPI_GEN_SETTINGS_ROW(1779), + SPI_GEN_SETTINGS_ROW(1695), + SPI_GEN_SETTINGS_ROW(1615), + SPI_GEN_SETTINGS_ROW(1539), + SPI_GEN_SETTINGS_ROW(1468), + SPI_GEN_SETTINGS_ROW(1398), + SPI_GEN_SETTINGS_ROW(1333), + SPI_GEN_SETTINGS_ROW(1271), + SPI_GEN_SETTINGS_ROW(1212), + SPI_GEN_SETTINGS_ROW(1155), + SPI_GEN_SETTINGS_ROW(1101), + SPI_GEN_SETTINGS_ROW(1049), + SPI_GEN_SETTINGS_ROW(1000), + SPI_GEN_SETTINGS_ROW(953), + SPI_GEN_SETTINGS_ROW(909), + SPI_GEN_SETTINGS_ROW(866), + SPI_GEN_SETTINGS_ROW(826), + SPI_GEN_SETTINGS_ROW(787), + SPI_GEN_SETTINGS_ROW(750), + SPI_GEN_SETTINGS_ROW(715), + SPI_GEN_SETTINGS_ROW(682), + SPI_GEN_SETTINGS_ROW(650), + SPI_GEN_SETTINGS_ROW(619), + SPI_GEN_SETTINGS_ROW(590), + SPI_GEN_SETTINGS_ROW(563), + SPI_GEN_SETTINGS_ROW(536), + SPI_GEN_SETTINGS_ROW(511), + SPI_GEN_SETTINGS_ROW(487), + SPI_GEN_SETTINGS_ROW(465), + SPI_GEN_SETTINGS_ROW(443), + SPI_GEN_SETTINGS_ROW(422), + SPI_GEN_SETTINGS_ROW(402), + SPI_GEN_SETTINGS_ROW(384), + SPI_GEN_SETTINGS_ROW(366), + SPI_GEN_SETTINGS_ROW(349), + SPI_GEN_SETTINGS_ROW(332), + SPI_GEN_SETTINGS_ROW(317), + SPI_GEN_SETTINGS_ROW(302), + SPI_GEN_SETTINGS_ROW(288), + SPI_GEN_SETTINGS_ROW(274), + SPI_GEN_SETTINGS_ROW(261), + SPI_GEN_SETTINGS_ROW(249), + SPI_GEN_SETTINGS_ROW(238), + SPI_GEN_SETTINGS_ROW(226), + SPI_GEN_SETTINGS_ROW(216), + SPI_GEN_SETTINGS_ROW(206), + SPI_GEN_SETTINGS_ROW(196), + SPI_GEN_SETTINGS_ROW(187), + SPI_GEN_SETTINGS_ROW(178), + SPI_GEN_SETTINGS_ROW(170), + SPI_GEN_SETTINGS_ROW(162), + SPI_GEN_SETTINGS_ROW(154), + SPI_GEN_SETTINGS_ROW(147), + SPI_GEN_SETTINGS_ROW(140), + SPI_GEN_SETTINGS_ROW(134), + SPI_GEN_SETTINGS_ROW(128), + SPI_GEN_SETTINGS_ROW(122), + SPI_GEN_SETTINGS_ROW(116), + SPI_GEN_SETTINGS_ROW(111), + SPI_GEN_SETTINGS_ROW(105), + SPI_GEN_SETTINGS_ROW(100), + SPI_GEN_SETTINGS_ROW(95.4), + SPI_GEN_SETTINGS_ROW(90.9), + SPI_GEN_SETTINGS_ROW(86.6), + SPI_GEN_SETTINGS_ROW(82.6), + SPI_GEN_SETTINGS_ROW(78.7), + SPI_GEN_SETTINGS_ROW(75.0), + SPI_GEN_SETTINGS_ROW(71.5), + SPI_GEN_SETTINGS_ROW(68.2), + SPI_GEN_SETTINGS_ROW(65.0), + SPI_GEN_SETTINGS_ROW(61.9), + SPI_GEN_SETTINGS_ROW(59.0), + SPI_GEN_SETTINGS_ROW(56.3), + SPI_GEN_SETTINGS_ROW(53.6), + SPI_GEN_SETTINGS_ROW(51.1), + }; + static volatile SPISetting_t SPICurrentSettings; +#endif + +#if (ARCH == ARCH_AVR8) + static const uint8_t SPIMaskFromSCKDuration[] PROGMEM = + { + #if (F_CPU == 8000000) + SPI_SPEED_FCPU_DIV_2, // AVRStudio = 8MHz SPI, Actual = 4MHz SPI + SPI_SPEED_FCPU_DIV_2, // AVRStudio = 4MHz SPI, Actual = 4MHz SPI + SPI_SPEED_FCPU_DIV_4, // AVRStudio = 2MHz SPI, Actual = 2MHz SPI + SPI_SPEED_FCPU_DIV_8, // AVRStudio = 1MHz SPI, Actual = 1MHz SPI + SPI_SPEED_FCPU_DIV_16, // AVRStudio = 500KHz SPI, Actual = 500KHz SPI + SPI_SPEED_FCPU_DIV_32, // AVRStudio = 250KHz SPI, Actual = 250KHz SPI + SPI_SPEED_FCPU_DIV_64, // AVRStudio = 125KHz SPI, Actual = 125KHz SPI + #elif (F_CPU == 16000000) + SPI_SPEED_FCPU_DIV_2, // AVRStudio = 8MHz SPI, Actual = 8MHz SPI + SPI_SPEED_FCPU_DIV_4, // AVRStudio = 4MHz SPI, Actual = 4MHz SPI + SPI_SPEED_FCPU_DIV_8, // AVRStudio = 2MHz SPI, Actual = 2MHz SPI + SPI_SPEED_FCPU_DIV_16, // AVRStudio = 1MHz SPI, Actual = 1MHz SPI + SPI_SPEED_FCPU_DIV_32, // AVRStudio = 500KHz SPI, Actual = 500KHz SPI + SPI_SPEED_FCPU_DIV_64, // AVRStudio = 250KHz SPI, Actual = 250KHz SPI + SPI_SPEED_FCPU_DIV_128 // AVRStudio = 125KHz SPI, Actual = 125KHz SPI + #elif (F_CPU == 32000000) + SPI_SPEED_FCPU_DIV_4, // AVRStudio = 8MHz SPI, Actual = 8MHz SPI + SPI_SPEED_FCPU_DIV_8, // AVRStudio = 4MHz SPI, Actual = 4MHz SPI + SPI_SPEED_FCPU_DIV_16, // AVRStudio = 2MHz SPI, Actual = 2MHz SPI + SPI_SPEED_FCPU_DIV_32, // AVRStudio = 1MHz SPI, Actual = 1MHz SPI + SPI_SPEED_FCPU_DIV_64, // AVRStudio = 500KHz SPI, Actual = 500KHz SPI + SPI_SPEED_FCPU_DIV_128, // AVRStudio = 250KHz SPI, Actual = 250KHz SPI + #elif (F_CPU == 48000000) + SPI_SPEED_FCPU_DIV_4, // AVRStudio = 8MHz SPI, Actual = 12MHz SPI + SPI_SPEED_FCPU_DIV_8, // AVRStudio = 4MHz SPI, Actual = 6MHz SPI + SPI_SPEED_FCPU_DIV_16, // AVRStudio = 2MHz SPI, Actual = 3MHz SPI + SPI_SPEED_FCPU_DIV_32, // AVRStudio = 1MHz SPI, Actual = 1,5MHz SPI + SPI_SPEED_FCPU_DIV_64, // AVRStudio = 500KHz SPI, Actual = 750KHz SPI + SPI_SPEED_FCPU_DIV_128, // AVRStudio = 250KHz SPI, Actual = 375KHz SPI + #else + #error No SPI prescaler masks for chosen F_CPU speed. + #endif + }; + #define SPI_TABLE_SIZE() (sizeof(SPIMaskFromSCKDuration)) + + /** Lookup table to convert the slower ISP speeds into a compare value for the software SPI driver. + * + * \hideinitializer + */ + static const uint16_t TimerCompareFromSCKDuration[] PROGMEM = + { + ISP_TIMER_COMP(96386), ISP_TIMER_COMP(89888), ISP_TIMER_COMP(84211), ISP_TIMER_COMP(79208), ISP_TIMER_COMP(74767), + ISP_TIMER_COMP(70797), ISP_TIMER_COMP(67227), ISP_TIMER_COMP(64000), ISP_TIMER_COMP(61069), ISP_TIMER_COMP(58395), + ISP_TIMER_COMP(55945), ISP_TIMER_COMP(51613), ISP_TIMER_COMP(49690), ISP_TIMER_COMP(47905), ISP_TIMER_COMP(46243), + ISP_TIMER_COMP(43244), ISP_TIMER_COMP(41885), ISP_TIMER_COMP(39409), ISP_TIMER_COMP(38278), ISP_TIMER_COMP(36200), + ISP_TIMER_COMP(34335), ISP_TIMER_COMP(32654), ISP_TIMER_COMP(31129), ISP_TIMER_COMP(29740), ISP_TIMER_COMP(28470), + ISP_TIMER_COMP(27304), ISP_TIMER_COMP(25724), ISP_TIMER_COMP(24768), ISP_TIMER_COMP(23461), ISP_TIMER_COMP(22285), + ISP_TIMER_COMP(21221), ISP_TIMER_COMP(20254), ISP_TIMER_COMP(19371), ISP_TIMER_COMP(18562), ISP_TIMER_COMP(17583), + ISP_TIMER_COMP(16914), ISP_TIMER_COMP(16097), ISP_TIMER_COMP(15356), ISP_TIMER_COMP(14520), ISP_TIMER_COMP(13914), + ISP_TIMER_COMP(13224), ISP_TIMER_COMP(12599), ISP_TIMER_COMP(12031), ISP_TIMER_COMP(11511), ISP_TIMER_COMP(10944), + ISP_TIMER_COMP(10431), ISP_TIMER_COMP(9963), ISP_TIMER_COMP(9468), ISP_TIMER_COMP(9081), ISP_TIMER_COMP(8612), + ISP_TIMER_COMP(8239), ISP_TIMER_COMP(7851), ISP_TIMER_COMP(7498), ISP_TIMER_COMP(7137), ISP_TIMER_COMP(6809), + ISP_TIMER_COMP(6478), ISP_TIMER_COMP(6178), ISP_TIMER_COMP(5879), ISP_TIMER_COMP(5607), ISP_TIMER_COMP(5359), + ISP_TIMER_COMP(5093), ISP_TIMER_COMP(4870), ISP_TIMER_COMP(4633), ISP_TIMER_COMP(4418), ISP_TIMER_COMP(4209), + ISP_TIMER_COMP(4019), ISP_TIMER_COMP(3823), ISP_TIMER_COMP(3645), ISP_TIMER_COMP(3474), ISP_TIMER_COMP(3310), + ISP_TIMER_COMP(3161), ISP_TIMER_COMP(3011), ISP_TIMER_COMP(2869), ISP_TIMER_COMP(2734), ISP_TIMER_COMP(2611), + ISP_TIMER_COMP(2484), ISP_TIMER_COMP(2369), ISP_TIMER_COMP(2257), ISP_TIMER_COMP(2152), ISP_TIMER_COMP(2052), + ISP_TIMER_COMP(1956), ISP_TIMER_COMP(1866), ISP_TIMER_COMP(1779), ISP_TIMER_COMP(1695), ISP_TIMER_COMP(1615), + ISP_TIMER_COMP(1539), ISP_TIMER_COMP(1468), ISP_TIMER_COMP(1398), ISP_TIMER_COMP(1333), ISP_TIMER_COMP(1271), + ISP_TIMER_COMP(1212), ISP_TIMER_COMP(1155), ISP_TIMER_COMP(1101), ISP_TIMER_COMP(1049), ISP_TIMER_COMP(1000), + ISP_TIMER_COMP(953), ISP_TIMER_COMP(909), ISP_TIMER_COMP(866), ISP_TIMER_COMP(826), ISP_TIMER_COMP(787), + ISP_TIMER_COMP(750), ISP_TIMER_COMP(715), ISP_TIMER_COMP(682), ISP_TIMER_COMP(650), ISP_TIMER_COMP(619), + ISP_TIMER_COMP(590), ISP_TIMER_COMP(563), ISP_TIMER_COMP(536), ISP_TIMER_COMP(511), ISP_TIMER_COMP(487), + ISP_TIMER_COMP(465), ISP_TIMER_COMP(443), ISP_TIMER_COMP(422), ISP_TIMER_COMP(402), ISP_TIMER_COMP(384), + ISP_TIMER_COMP(366), ISP_TIMER_COMP(349), ISP_TIMER_COMP(332), ISP_TIMER_COMP(317), ISP_TIMER_COMP(302), + ISP_TIMER_COMP(288), ISP_TIMER_COMP(274), ISP_TIMER_COMP(261), ISP_TIMER_COMP(249), ISP_TIMER_COMP(238), + ISP_TIMER_COMP(226), ISP_TIMER_COMP(216), ISP_TIMER_COMP(206), ISP_TIMER_COMP(196), ISP_TIMER_COMP(187), + ISP_TIMER_COMP(178), ISP_TIMER_COMP(170), ISP_TIMER_COMP(162), ISP_TIMER_COMP(154), ISP_TIMER_COMP(147), + ISP_TIMER_COMP(140), ISP_TIMER_COMP(134), ISP_TIMER_COMP(128), ISP_TIMER_COMP(122), ISP_TIMER_COMP(116), + ISP_TIMER_COMP(111), ISP_TIMER_COMP(105), ISP_TIMER_COMP(100), ISP_TIMER_COMP(95.4), ISP_TIMER_COMP(90.9), + ISP_TIMER_COMP(86.6), ISP_TIMER_COMP(82.6), ISP_TIMER_COMP(78.7), ISP_TIMER_COMP(75.0), ISP_TIMER_COMP(71.5), + ISP_TIMER_COMP(68.2), ISP_TIMER_COMP(65.0), ISP_TIMER_COMP(61.9), ISP_TIMER_COMP(59.0), ISP_TIMER_COMP(56.3), + ISP_TIMER_COMP(53.6), ISP_TIMER_COMP(51.1) + }; + #endif -}; -/** Lookup table to convert the slower ISP speeds into a compare value for the software SPI driver. - * - * \hideinitializer - */ -static const uint16_t TimerCompareFromSCKDuration[] PROGMEM = -{ - ISP_TIMER_COMP(96386), ISP_TIMER_COMP(89888), ISP_TIMER_COMP(84211), ISP_TIMER_COMP(79208), ISP_TIMER_COMP(74767), - ISP_TIMER_COMP(70797), ISP_TIMER_COMP(67227), ISP_TIMER_COMP(64000), ISP_TIMER_COMP(61069), ISP_TIMER_COMP(58395), - ISP_TIMER_COMP(55945), ISP_TIMER_COMP(51613), ISP_TIMER_COMP(49690), ISP_TIMER_COMP(47905), ISP_TIMER_COMP(46243), - ISP_TIMER_COMP(43244), ISP_TIMER_COMP(41885), ISP_TIMER_COMP(39409), ISP_TIMER_COMP(38278), ISP_TIMER_COMP(36200), - ISP_TIMER_COMP(34335), ISP_TIMER_COMP(32654), ISP_TIMER_COMP(31129), ISP_TIMER_COMP(29740), ISP_TIMER_COMP(28470), - ISP_TIMER_COMP(27304), ISP_TIMER_COMP(25724), ISP_TIMER_COMP(24768), ISP_TIMER_COMP(23461), ISP_TIMER_COMP(22285), - ISP_TIMER_COMP(21221), ISP_TIMER_COMP(20254), ISP_TIMER_COMP(19371), ISP_TIMER_COMP(18562), ISP_TIMER_COMP(17583), - ISP_TIMER_COMP(16914), ISP_TIMER_COMP(16097), ISP_TIMER_COMP(15356), ISP_TIMER_COMP(14520), ISP_TIMER_COMP(13914), - ISP_TIMER_COMP(13224), ISP_TIMER_COMP(12599), ISP_TIMER_COMP(12031), ISP_TIMER_COMP(11511), ISP_TIMER_COMP(10944), - ISP_TIMER_COMP(10431), ISP_TIMER_COMP(9963), ISP_TIMER_COMP(9468), ISP_TIMER_COMP(9081), ISP_TIMER_COMP(8612), - ISP_TIMER_COMP(8239), ISP_TIMER_COMP(7851), ISP_TIMER_COMP(7498), ISP_TIMER_COMP(7137), ISP_TIMER_COMP(6809), - ISP_TIMER_COMP(6478), ISP_TIMER_COMP(6178), ISP_TIMER_COMP(5879), ISP_TIMER_COMP(5607), ISP_TIMER_COMP(5359), - ISP_TIMER_COMP(5093), ISP_TIMER_COMP(4870), ISP_TIMER_COMP(4633), ISP_TIMER_COMP(4418), ISP_TIMER_COMP(4209), - ISP_TIMER_COMP(4019), ISP_TIMER_COMP(3823), ISP_TIMER_COMP(3645), ISP_TIMER_COMP(3474), ISP_TIMER_COMP(3310), - ISP_TIMER_COMP(3161), ISP_TIMER_COMP(3011), ISP_TIMER_COMP(2869), ISP_TIMER_COMP(2734), ISP_TIMER_COMP(2611), - ISP_TIMER_COMP(2484), ISP_TIMER_COMP(2369), ISP_TIMER_COMP(2257), ISP_TIMER_COMP(2152), ISP_TIMER_COMP(2052), - ISP_TIMER_COMP(1956), ISP_TIMER_COMP(1866), ISP_TIMER_COMP(1779), ISP_TIMER_COMP(1695), ISP_TIMER_COMP(1615), - ISP_TIMER_COMP(1539), ISP_TIMER_COMP(1468), ISP_TIMER_COMP(1398), ISP_TIMER_COMP(1333), ISP_TIMER_COMP(1271), - ISP_TIMER_COMP(1212), ISP_TIMER_COMP(1155), ISP_TIMER_COMP(1101), ISP_TIMER_COMP(1049), ISP_TIMER_COMP(1000), - ISP_TIMER_COMP(953), ISP_TIMER_COMP(909), ISP_TIMER_COMP(866), ISP_TIMER_COMP(826), ISP_TIMER_COMP(787), - ISP_TIMER_COMP(750), ISP_TIMER_COMP(715), ISP_TIMER_COMP(682), ISP_TIMER_COMP(650), ISP_TIMER_COMP(619), - ISP_TIMER_COMP(590), ISP_TIMER_COMP(563), ISP_TIMER_COMP(536), ISP_TIMER_COMP(511), ISP_TIMER_COMP(487), - ISP_TIMER_COMP(465), ISP_TIMER_COMP(443), ISP_TIMER_COMP(422), ISP_TIMER_COMP(402), ISP_TIMER_COMP(384), - ISP_TIMER_COMP(366), ISP_TIMER_COMP(349), ISP_TIMER_COMP(332), ISP_TIMER_COMP(317), ISP_TIMER_COMP(302), - ISP_TIMER_COMP(288), ISP_TIMER_COMP(274), ISP_TIMER_COMP(261), ISP_TIMER_COMP(249), ISP_TIMER_COMP(238), - ISP_TIMER_COMP(226), ISP_TIMER_COMP(216), ISP_TIMER_COMP(206), ISP_TIMER_COMP(196), ISP_TIMER_COMP(187), - ISP_TIMER_COMP(178), ISP_TIMER_COMP(170), ISP_TIMER_COMP(162), ISP_TIMER_COMP(154), ISP_TIMER_COMP(147), - ISP_TIMER_COMP(140), ISP_TIMER_COMP(134), ISP_TIMER_COMP(128), ISP_TIMER_COMP(122), ISP_TIMER_COMP(116), - ISP_TIMER_COMP(111), ISP_TIMER_COMP(105), ISP_TIMER_COMP(100), ISP_TIMER_COMP(95.4), ISP_TIMER_COMP(90.9), - ISP_TIMER_COMP(86.6), ISP_TIMER_COMP(82.6), ISP_TIMER_COMP(78.7), ISP_TIMER_COMP(75.0), ISP_TIMER_COMP(71.5), - ISP_TIMER_COMP(68.2), ISP_TIMER_COMP(65.0), ISP_TIMER_COMP(61.9), ISP_TIMER_COMP(59.0), ISP_TIMER_COMP(56.3), - ISP_TIMER_COMP(53.6), ISP_TIMER_COMP(51.1) -}; + /** Currently selected SPI driver, either hardware (for fast ISP speeds) or software (for slower ISP speeds). */ bool ISPTarget_HardwareSPIMode = true; @@ -113,8 +342,8 @@ static volatile uint8_t ISPTarget_SoftSPI_Data; /** Number of bits left to transfer in the software SPI driver */ static volatile uint8_t ISPTarget_SoftSPI_BitsRemaining; - /** ISR to handle software SPI transmission and reception */ +#if ARCH == ARCH_AVR8 ISR(TIMER1_COMPA_vect, ISR_BLOCK) { /* Check if rising edge (output next bit) or falling edge (read in next bit) */ @@ -142,6 +371,40 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK) /* Fast toggle of PORTB.1 via the PIN register (see datasheet) */ PINB |= (1 << 1); } +#elif ARCH == ARCH_XMEGA +ISR(SW_SPI_TIMER_CCB_vect, ISR_BLOCK) +{ + /* Falling edge and setup MOSI data */ + SPI_PORT.OUTCLR = SPI_SCK_MASK; + + if(ISPTarget_SoftSPI_BitsRemaining) + { + if (ISPTarget_SoftSPI_Data & (1 << 7)) + SPI_PORT.OUTSET = SPI_MOSI_MASK; + else + SPI_PORT.OUTCLR = SPI_MOSI_MASK; + } + else + { + //No more bits + SPI_PORT.OUTSET = SPI_MOSI_MASK; + SW_SPI_TIMER.CTRLA = TC_CLKSEL_OFF_gc; + } + +} + +ISR(SW_SPI_TIMER_OVF_vect, ISR_BLOCK) +{ + /* Rising edge and read MISO data */ + SPI_PORT.OUTSET = SPI_SCK_MASK; + + ISPTarget_SoftSPI_Data <<= 1; + ISPTarget_SoftSPI_BitsRemaining--; + + if (SPI_PORT.IN & SPI_MISO_MASK) + ISPTarget_SoftSPI_Data |= (1 << 0); +} +#endif /** Initializes the appropriate SPI driver (hardware or software, depending on the selected ISP speed) ready for * communication with the attached target. @@ -149,23 +412,66 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK) void ISPTarget_EnableTargetISP(void) { uint8_t SCKDuration = V2Params_GetParameterValue(PARAM_SCK_DURATION); + + #if (ARCH == ARCH_AVR8) + if (SCKDuration < SPI_TABLE_SIZE()) + { + ISPTarget_HardwareSPIMode = true; + + SPI_Init(pgm_read_byte(&SPIMaskFromSCKDuration[SCKDuration]) | SPI_ORDER_MSB_FIRST | + SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER); + } + else + { + ISPTarget_HardwareSPIMode = false; + DDRB |= ((1 << 1) | (1 << 2)); //MOSI and SCK High + PORTB |= ((1 << 0) | (1 << 3)); //Pullup on RST and MISO - if (SCKDuration < sizeof(SPIMaskFromSCKDuration)) - { - ISPTarget_HardwareSPIMode = true; - - SPI_Init(pgm_read_byte(&SPIMaskFromSCKDuration[SCKDuration]) | SPI_ORDER_MSB_FIRST | - SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER); - } - else - { - ISPTarget_HardwareSPIMode = false; - - DDRB |= ((1 << 1) | (1 << 2)); - PORTB |= ((1 << 0) | (1 << 3)); - - ISPTarget_ConfigureSoftwareSPI(SCKDuration); - } + ISPTarget_ConfigureSoftwareSPI(SCKDuration); + } + #elif (ARCH == ARCH_XMEGA) + //We need to default agains slowest value (AVR096) + if(SCKDuration >= sizeof(SPISettings)/sizeof(SPISettings[0])) + SCKDuration = sizeof(SPISettings)/sizeof(SPISettings[0]) - 1; + //Copy the selected line into RAM. For easy access on Precalculated values + memcpy_P((void *)&SPICurrentSettings, &SPISettings[SCKDuration], sizeof(SPICurrentSettings)); + + + if(!SPICurrentSettings.hardware_spi) + { + /* If the Frequency is too low we need to select software spi */ + ISPTarget_HardwareSPIMode = false; + SPI_PORT.DIRSET = SPI_SCK_MASK | SPI_MOSI_MASK; + SPI_PORT.DIRCLR = SPI_MISO_MASK; + SPI_PORT.AUX_LINE_CTRL = PORT_OPC_PULLUP_gc; + SPI_PORT.SPI_MISO_CTRL = PORT_OPC_PULLUP_gc; + ISPTarget_ConfigureSoftwareSPI(SCKDuration); + } + else + { + /* If we can be slow enough for HW Spi we are going to use it */ + ISPTarget_HardwareSPIMode = true; + //REMAP only available if Standalone SPI module is selected + #if defined(REMAP_SPI) && !defined(USART_SPI_MASTER) + PDI_PORT.REMAP |= PORT_SPI_bm; + #endif + + /* Setup pins */ + SPI_PORT.DIRSET = SPI_SCK_MASK | SPI_MOSI_MASK | PIN4_bm; + SPI_PORT.DIRCLR = SPI_MISO_MASK; + SPI_PORT.OUTSET = PIN4_bm; + #if defined(USART_SPI_MASTER) + //Use Precalculated values for setup SPI + SerialSPI_Init(&USART_SPI_REG, (USART_SPI_SCK_LEAD_RISING | USART_SPI_SAMPLE_LEADING | USART_SPI_ORDER_MSB_FIRST), 200000); + //Sadly hacky but needed, as we have BSEL not the Frequency... + USART_SPI_REG.BAUDCTRLB = (SPICurrentSettings.value >> 8); + USART_SPI_REG.BAUDCTRLA = (SPICurrentSettings.value & 0xFF); + #else + SPI_Init(&SPI_REG, (SPICurrentSettings.value & 0xFF) | SPI_ORDER_MSB_FIRST | + SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER); + #endif + } + #endif } /** Shuts down the current selected SPI driver (hardware or software, depending on the selected ISP speed) so that no @@ -173,6 +479,7 @@ void ISPTarget_EnableTargetISP(void) */ void ISPTarget_DisableTargetISP(void) { +#if (ARCH == ARCH_AVR8) if (ISPTarget_HardwareSPIMode) { SPI_Disable(); @@ -186,6 +493,30 @@ void ISPTarget_DisableTargetISP(void) * re-purposed for software SPI */ ISPTarget_ConfigureRescueClock(); } +#elif (ARCH == ARCH_XMEGA) + if (SPICurrentSettings.hardware_spi) + { + #if defined(USART_SPI_MASTER) + SerialSPI_Disable(&USART_SPI_REG); + #else + SPI_Disable(&SPI_REG); + #endif + #if defined(REMAP_SPI) + PDI_PORT.REMAP &= ~PORT_SPI_bm; + #endif + SPI_PORT.DIRCLR = SPI_SCK_MASK | SPI_MISO_MASK | SPI_MOSI_MASK | PIN4_bm; + } + else + { + SPI_PORT.DIRCLR = SPI_SCK_MASK | SPI_MOSI_MASK; + SPI_PORT.AUX_LINE_CTRL &= ~PORT_OPC_PULLUP_gc; + SPI_PORT.SPI_MOSI_CTRL &= ~PORT_OPC_PULLUP_gc; + + /* Must re-enable rescue clock once software ISP has exited, as the timer for the rescue clock is + * re-purposed for software SPI */ + ISPTarget_ConfigureRescueClock(); + } +#endif } /** Configures the AVR to produce a 4MHz rescue clock out of the OCR1A pin of the AVR, so @@ -195,6 +526,7 @@ void ISPTarget_DisableTargetISP(void) */ void ISPTarget_ConfigureRescueClock(void) { +#if (ARCH == ARCH_AVR8) #if defined(XCK_RESCUE_CLOCK_ENABLE) /* Configure XCK as an output for the specified AVR model */ DDRD |= (1 << 5); @@ -218,6 +550,17 @@ void ISPTarget_ConfigureRescueClock(void) TCCR1A = (1 << COM1A0); TCCR1B = ((1 << WGM12) | (1 << CS10)); #endif +#elif (ARCH == ARCH_XMEGA) + #if defined(XCK_RESCUE_CLOCK_ENABLE) + #warning "XCK Rescue clock not implemented for xmega falling back to default" + #endif + RESCUE_PORT.DIRSET = RESCUE_PIN_MASK; + RESCUE_PORT.OUTSET = RESCUE_PIN_MASK; + RESCUE_TIMER.CTRLA = TC_CLKSEL_DIV1_gc; + RESCUE_TIMER.CTRLB = TC_WGMODE_SINGLESLOPE_gc | RESCUE_TIMER_CMP_EN; + RESCUE_TIMER.RESCUE_TIMER_CMP_REG = (F_CPU / 2 / ISP_RESCUE_CLOCK_SPEED); + RESCUE_TIMER.PER = (F_CPU / ISP_RESCUE_CLOCK_SPEED) - 1; +#endif } /** Configures the AVR's timer ready to produce software SPI for the slower ISP speeds that @@ -227,12 +570,21 @@ void ISPTarget_ConfigureRescueClock(void) */ void ISPTarget_ConfigureSoftwareSPI(const uint8_t SCKDuration) { +#if ARCH == ARCH_AVR8 /* Configure Timer 1 for software SPI using the specified SCK duration */ TIMSK1 = (1 << OCIE1A); TCNT1 = 0; OCR1A = pgm_read_word(&TimerCompareFromSCKDuration[SCKDuration - sizeof(SPIMaskFromSCKDuration)]); TCCR1A = 0; TCCR1B = 0; +#elif (ARCH == ARCH_XMEGA) + SW_SPI_TIMER.CTRLA = TC_CLKSEL_OFF_gc; + SW_SPI_TIMER.INTCTRLA = TC_OVFINTLVL_OFF_gc; + SW_SPI_TIMER.CNT = 0; + SW_SPI_TIMER.CCB = SPICurrentSettings.value - 1; + SW_SPI_TIMER.PER = SPICurrentSettings.value * 2 - 1; + SW_SPI_TIMER.CTRLB = TC_WGMODE_NORMAL_gc; +#endif } /** Sends and receives a single byte of data to and from the attached target via software SPI. @@ -246,6 +598,7 @@ uint8_t ISPTarget_TransferSoftSPIByte(const uint8_t Byte) ISPTarget_SoftSPI_Data = Byte; ISPTarget_SoftSPI_BitsRemaining = 8; +#if ARCH == ARCH_AVR8 /* Set initial MOSI pin state according to the byte to be transferred */ if (ISPTarget_SoftSPI_Data & (1 << 7)) PORTB |= (1 << 2); @@ -256,7 +609,17 @@ uint8_t ISPTarget_TransferSoftSPIByte(const uint8_t Byte) TCCR1B = ((1 << WGM12) | (1 << CS11)); while (ISPTarget_SoftSPI_BitsRemaining && TimeoutTicksRemaining); TCCR1B = 0; - +#elif (ARCH == ARCH_XMEGA) + SW_SPI_TIMER.CTRLA = TC_CLKSEL_OFF_gc; + SW_SPI_TIMER.CNT = 0; + SW_SPI_TIMER.INTCTRLA = TC_OVFINTLVL_MED_gc; + SW_SPI_TIMER.INTCTRLB = TC_CCBINTLVL_MED_gc; + SW_SPI_TIMER.CTRLA = SPICurrentSettings.prediv; + while (SW_SPI_TIMER.CTRLA & TC0_CLKSEL_gm) + ; + SW_SPI_TIMER.INTCTRLA = TC_OVFINTLVL_OFF_gc; + SW_SPI_TIMER.INTCTRLB = TC_CCBINTLVL_OFF_gc; +#endif return ISPTarget_SoftSPI_Data; } @@ -267,6 +630,7 @@ uint8_t ISPTarget_TransferSoftSPIByte(const uint8_t Byte) */ void ISPTarget_ChangeTargetResetLine(const bool ResetTarget) { +#if (ARCH == ARCH_AVR8) if (ResetTarget) { AUX_LINE_DDR |= AUX_LINE_MASK; @@ -281,6 +645,23 @@ void ISPTarget_ChangeTargetResetLine(const bool ResetTarget) AUX_LINE_DDR &= ~AUX_LINE_MASK; AUX_LINE_PORT &= ~AUX_LINE_MASK; } +#elif (ARCH == ARCH_XMEGA) + if (ResetTarget) + { + AUX_LINE_PORT.DIRSET = AUX_LINE_MASK; + + if (!(V2Params_GetParameterValue(PARAM_RESET_POLARITY))) + AUX_LINE_PORT.OUTSET = AUX_LINE_MASK; + else + AUX_LINE_PORT.OUTCLR = AUX_LINE_MASK; + } + else + { + AUX_LINE_PORT.DIRCLR = AUX_LINE_MASK; + AUX_LINE_PORT.OUTCLR = AUX_LINE_MASK; + AUX_LINE_PORT.AUX_LINE_CTRL &= ~PORT_OPC_PULLUP_gc; + } +#endif } /** Waits until the target has completed the last operation, by continuously polling the device's diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.h b/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.h index 3b43ef581..9ab11f36d 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.h +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPTarget.h @@ -42,11 +42,16 @@ #include #include - #include + #include "../V2Protocol.h" #include "ISPProtocol.h" #include "Config/AppConfig.h" + #if defined(USART_SPI_MASTER) + #include + #else + #include + #endif /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) @@ -62,8 +67,11 @@ #define LOAD_EXTENDED_ADDRESS_CMD 0x4D /** Macro to convert an ISP frequency to a number of timer clock cycles for the software SPI driver. */ - #define ISP_TIMER_COMP(freq) (((F_CPU / 8) / 2 / freq) - 1) - + #if (ARCH == ARCH_XMEGA) + #define ISP_TIMER_COMP(prediv, freq) (F_CPU / (prediv * 2ULL * freq)) + #else + #define ISP_TIMER_COMP(freq) (((F_CPU / 8) / 2 / freq) - 1) + #endif /** ISP rescue clock speed in Hz, for clocking targets with incorrectly set fuses. */ #define ISP_RESCUE_CLOCK_SPEED 4000000 @@ -94,7 +102,15 @@ static inline void ISPTarget_SendByte(const uint8_t Byte) { if (ISPTarget_HardwareSPIMode) + #if (ARCH == ARCH_XMEGA) + #ifdef USART_SPI_MASTER + SerialSPI_SendByte(&USART_SPI_REG, Byte); + #else + SPI_SendByte(&SPI_REG, Byte); + #endif + #else SPI_SendByte(Byte); + #endif else ISPTarget_TransferSoftSPIByte(Byte); } @@ -109,7 +125,15 @@ uint8_t ReceivedByte; if (ISPTarget_HardwareSPIMode) + #if (ARCH == ARCH_XMEGA) + #ifdef USART_SPI_MASTER + ReceivedByte = SerialSPI_ReceiveByte(&USART_SPI_REG); + #else + ReceivedByte = SPI_ReceiveByte(&SPI_REG); + #endif + #else ReceivedByte = SPI_ReceiveByte(); + #endif else ReceivedByte = ISPTarget_TransferSoftSPIByte(0x00); @@ -132,7 +156,15 @@ uint8_t ReceivedByte; if (ISPTarget_HardwareSPIMode) - ReceivedByte = SPI_TransferByte(Byte); + #if (ARCH == ARCH_XMEGA) + #ifdef USART_SPI_MASTER + ReceivedByte = SerialSPI_TransferByte(&USART_SPI_REG, Byte); + #else + ReceivedByte = SPI_TransferByte(&SPI_REG, Byte); + #endif + #else + ReceivedByte = SPI_TransferByte(Byte); + #endif else ReceivedByte = ISPTarget_TransferSoftSPIByte(Byte); diff --git a/Projects/AVRISP-MKII/Lib/V2Protocol.c b/Projects/AVRISP-MKII/Lib/V2Protocol.c index 8fee1d63b..5d7c1f66b 100644 --- a/Projects/AVRISP-MKII/Lib/V2Protocol.c +++ b/Projects/AVRISP-MKII/Lib/V2Protocol.c @@ -42,7 +42,7 @@ uint32_t CurrentAddress; /** Flag to indicate that the next read/write operation must update the device's current extended FLASH address */ bool MustLoadExtendedAddress; - +#if ARCH == ARCH_AVR8 /** ISR to manage timeouts whilst processing a V2Protocol command */ ISR(TIMER0_COMPA_vect, ISR_NOBLOCK) { @@ -51,6 +51,15 @@ ISR(TIMER0_COMPA_vect, ISR_NOBLOCK) else TCCR0B = 0; } +#elif ARCH == ARCH_XMEGA +ISR(DELAY_TIMER_OVF_vect, ISR_NOBLOCK) +{ + if (TimeoutTicksRemaining) + TimeoutTicksRemaining--; + else + DELAY_TIMER.CTRLA = TC_CLKSEL_OFF_gc; +} +#endif /** Initializes the hardware and software associated with the V2 protocol command handling. */ void V2Protocol_Init(void) @@ -60,12 +69,36 @@ void V2Protocol_Init(void) ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_128); ADC_SetupChannel(VTARGET_ADC_CHANNEL); ADC_StartReading(VTARGET_REF_MASK | ADC_RIGHT_ADJUSTED | VTARGET_ADC_CHANNEL_MASK); + #elif !defined(NO_VTARGET_DETECT) && (ARCH == ARCH_XMEGA) + //TODO: Write LUFA XMega ADC Driver + NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc; + uint8_t cal = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0)); + NVM_CMD = NVM_CMD_NO_OPERATION_gc; + ADCA.CALL = cal; + + NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc; + cal = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1)); + NVM_CMD = NVM_CMD_NO_OPERATION_gc; + ADCA.CALH = cal; + ADCA.CTRLB = ADC_FREERUN_bm | ADC_IMPMODE_bm; + PORTA.DIRCLR = PIN0_bm; + ADCA.REFCTRL = ADC_REFSEL_INT1V_gc; + ADCA.PRESCALER = ADC_PRESCALER_DIV64_gc; + ADCA.CH0.CTRL = ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc; + ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN0_gc; + ADCA.CTRLA = ADC_ENABLE_bm; #endif /* Timeout timer initialization (~10ms period) */ +#if ARCH == ARCH_AVR8 OCR0A = (((F_CPU / 1024) / 100) - 1); TCCR0A = (1 << WGM01); TIMSK0 = (1 << OCIE0A); +#elif ARCH == ARCH_XMEGA + DELAY_TIMER.PER = (((F_CPU / 1024) / 100) - 1); + DELAY_TIMER.CTRLB = TC_WGMODE_NORMAL_gc; + DELAY_TIMER.INTCTRLA = TC_OVFINTLVL_MED_gc; +#endif V2Params_LoadNonVolatileParamValues(); @@ -84,8 +117,11 @@ void V2Protocol_ProcessCommand(void) /* Reset timeout counter duration and start the timer */ TimeoutTicksRemaining = COMMAND_TIMEOUT_TICKS; +#if ARCH == ARCH_AVR8 TCCR0B = ((1 << CS02) | (1 << CS00)); - +#elif ARCH == ARCH_XMEGA + DELAY_TIMER.CTRLA = TC_CLKSEL_DIV1024_gc; +#endif switch (V2Command) { case CMD_SIGN_ON: @@ -150,8 +186,12 @@ void V2Protocol_ProcessCommand(void) } /* Disable the timeout management timer */ +#if ARCH == ARCH_AVR8 TCCR0B = 0; - +#elif ARCH == ARCH_XMEGA + DELAY_TIMER.CTRLA = TC_CLKSEL_OFF_gc; +#endif + Endpoint_WaitUntilReady(); Endpoint_SelectEndpoint(AVRISP_DATA_OUT_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT); diff --git a/Projects/AVRISP-MKII/Lib/V2ProtocolParams.c b/Projects/AVRISP-MKII/Lib/V2ProtocolParams.c index c42c6c4bb..b25ed2dab 100644 --- a/Projects/AVRISP-MKII/Lib/V2ProtocolParams.c +++ b/Projects/AVRISP-MKII/Lib/V2ProtocolParams.c @@ -139,6 +139,17 @@ void V2Params_UpdateParamValues(void) #if (defined(ADC) && !defined(NO_VTARGET_DETECT)) /* Update VTARGET parameter with the latest ADC conversion of VTARGET on supported AVR models */ V2Params_GetParamFromTable(PARAM_VTARGET)->ParamValue = (((uint16_t)(VTARGET_REF_VOLTS * 10 * VTARGET_SCALE_FACTOR) * ADC_GetResult()) / 1024); + #elif !defined(NO_VTARGET_DETECT) && (ARCH == ARCH_XMEGA) + uint32_t result = 0; + for(uint8_t i = 0; i < 64; i++) + { + while(!(ADCA.CH0.INTFLAGS & ADC_CH0IF_bm)) + ; + result += ADCA.CH0.RES; + ADCA.CH0.INTFLAGS = ADC_CH0IF_bm; + } + result >>= 6; + V2Params_GetParamFromTable(PARAM_VTARGET)->ParamValue = (((uint16_t)(VTARGET_REF_VOLTS * 10 * VTARGET_SCALE_FACTOR) * result) / 4096); #endif } diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c b/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c index 246d10bde..3b071c086 100644 --- a/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c +++ b/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c @@ -255,8 +255,11 @@ bool XMEGANVM_ReadMemory(const uint32_t ReadAddress, { /* Send a LDS command with the read address to read out the requested byte */ XPROGTarget_SendByte(PDI_CMD_LDS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE)); + XMEGANVM_SendAddress(ReadAddress); + *(ReadBuffer++) = XPROGTarget_ReceiveByte(); + } return (TimeoutTicksRemaining > 0); diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XPROGProtocol.c b/Projects/AVRISP-MKII/Lib/XPROG/XPROGProtocol.c index 5926e2a56..43a03c20f 100644 --- a/Projects/AVRISP-MKII/Lib/XPROG/XPROGProtocol.c +++ b/Projects/AVRISP-MKII/Lib/XPROG/XPROGProtocol.c @@ -250,7 +250,7 @@ static void XPROGProtocol_WriteMemory(void) WriteMemory_XPROG_Params.Length = SwapEndian_16(WriteMemory_XPROG_Params.Length); Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NULL); - if (WriteMemory_XPROG_Params.Length >= sizeof(WriteMemory_XPROG_Params.ProgData)) + if (WriteMemory_XPROG_Params.Length > sizeof(WriteMemory_XPROG_Params.ProgData)) { Endpoint_StallTransaction(); return; @@ -322,6 +322,7 @@ static void XPROGProtocol_WriteMemory(void) ReturnStatus = XPROG_ERR_TIMEOUT; } } + Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_WRITE_MEM); @@ -375,7 +376,7 @@ static void XPROGProtocol_ReadMemory(void) Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_READ_MEM); Endpoint_Write_8(ReturnStatus); - + if (ReturnStatus == XPROG_ERR_OK) Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length, NULL); diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c index ce3d75983..50721112d 100644 --- a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c +++ b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c @@ -45,7 +45,7 @@ static bool IsSending; void XPROGTarget_EnableTargetPDI(void) { IsSending = false; - +#if (ARCH == ARCH_AVR8) /* Set Tx and XCK as outputs, Rx as input */ DDRD |= (1 << 5) | (1 << 3); DDRD &= ~(1 << 2); @@ -64,6 +64,29 @@ void XPROGTarget_EnableTargetPDI(void) UCSR1B = (1 << TXEN1); UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); + +#elif (ARCH == ARCH_XMEGA) + /* Set Tx and XCK as outputs, Rx as input, Invert the XCK PIN */ + PDI_PORT.DIRSET = PDI_TX_MASK | PDI_XCK_MASK; + PDI_PORT.DIRCLR = PDI_RX_MASK; + PDI_PORT.PDI_XCK_CTRL = PORT_INVEN_bm; + + /* Set Tx (PDI CLOCK) high (Set low because its inverted), DATA line low for at least 90ns to disable /RESET functionality */ + PDI_PORT.OUTCLR = PDI_TX_MASK; + PDI_PORT.OUTSET = PDI_XCK_MASK; + _delay_us(100); + + /* Set DATA line high for at least 90ns to disable /RESET functionality */ + PDI_PORT.OUTSET = PDI_TX_MASK; + _delay_us(20); + + /* Set up the synchronous USART for XMEGA communications - 8 data bits, even parity, 2 stop bits */ + PDI_USART.BAUDCTRLA = ((((uint32_t)F_CPU + XPROG_HARDWARE_SPEED) /(2*XPROG_HARDWARE_SPEED)) - 1) & 0xFF; + PDI_USART.BAUDCTRLB = ((((uint32_t)F_CPU + XPROG_HARDWARE_SPEED) /(2*XPROG_HARDWARE_SPEED)) - 1) >> 8; + PDI_USART.CTRLA = 0; + PDI_USART.CTRLB = USART_TXEN_bm | USART_CLK2X_bm; + PDI_USART.CTRLC = USART_CMODE_SYNCHRONOUS_gc | USART_PMODE_EVEN_gc | USART_SBMODE_bm | USART_CHSIZE_8BIT_gc; +#endif /* Send two IDLEs of 12 bits each to enable PDI interface (need at least 16 idle bits) */ XPROGTarget_SendIdle(); XPROGTarget_SendIdle(); @@ -74,6 +97,7 @@ void XPROGTarget_EnableTargetTPI(void) { IsSending = false; +#if (ARCH == ARCH_AVR8) /* Set /RESET line low for at least 400ns to enable TPI functionality */ AUX_LINE_DDR |= AUX_LINE_MASK; AUX_LINE_PORT &= ~AUX_LINE_MASK; @@ -87,7 +111,24 @@ void XPROGTarget_EnableTargetTPI(void) UBRR1 = ((F_CPU / 2 / XPROG_HARDWARE_SPEED) - 1); UCSR1B = (1 << TXEN1); UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); +#elif (ARCH == ARCH_XMEGA) + /* Set /RESET line low for at least 400ns to enable TPI functionality */ + AUX_LINE_PORT.DIRSET = AUX_LINE_MASK; + AUX_LINE_PORT.OUTCLR = AUX_LINE_MASK; + _delay_us(100); + + /* Set Tx and XCK as outputs, Rx as input, Invert XCK */ + PDI_PORT.DIRSET = PDI_TX_MASK | PDI_XCK_MASK; + PDI_PORT.DIRCLR = PDI_RX_MASK; + PDI_PORT.PDI_XCK_CTRL = PORT_INVEN_bm; + /* Set up the synchronous USART for TPI communications - 8 data bits, even parity, 2 stop bits */ + PDI_USART.BAUDCTRLA = ((((uint32_t)F_CPU + XPROG_HARDWARE_SPEED) /(2*XPROG_HARDWARE_SPEED)) - 1) & 0xFF; + PDI_USART.BAUDCTRLB = ((((uint32_t)F_CPU + XPROG_HARDWARE_SPEED) /(2*XPROG_HARDWARE_SPEED)) - 1) >> 8; + PDI_USART.CTRLA = 0; + PDI_USART.CTRLB = USART_TXEN_bm | USART_CLK2X_bm; + PDI_USART.CTRLC = USART_CMODE_SYNCHRONOUS_gc | USART_PMODE_EVEN_gc | USART_SBMODE_bm | USART_CHSIZE_8BIT_gc; +#endif /* Send two IDLEs of 12 bits each to enable TPI interface (need at least 16 idle bits) */ XPROGTarget_SendIdle(); XPROGTarget_SendIdle(); @@ -100,6 +141,7 @@ void XPROGTarget_DisableTargetPDI(void) if (IsSending) XPROGTarget_SetRxMode(); +#if (ARCH == ARCH_AVR8) /* Turn off receiver and transmitter of the USART, clear settings */ UCSR1A = ((1 << TXC1) | (1 << RXC1)); UCSR1B = 0; @@ -108,6 +150,20 @@ void XPROGTarget_DisableTargetPDI(void) /* Tristate all pins */ DDRD &= ~((1 << 5) | (1 << 3)); PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2)); +#elif (ARCH == ARCH_XMEGA) + /* Turn off receiver and transmitter of the USART, clear settings */ + PDI_USART.STATUS = USART_RXCIF_bm | USART_TXCIF_bm; + PDI_USART.CTRLA = 0; + PDI_USART.CTRLB = 0; + PDI_USART.CTRLC = 0; + + /* Tristate all pins and disable inversion */ + PDI_PORT.DIRCLR = PDI_TX_MASK | PDI_XCK_MASK; + + PDI_PORT.PDI_XCK_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc | PORT_INVEN_bm); + PDI_PORT.PDI_TX_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc); + PDI_PORT.PDI_RX_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc); +#endif } /** Disables the target's TPI interface, exits programming mode and starts the target's application. */ @@ -117,6 +173,7 @@ void XPROGTarget_DisableTargetTPI(void) if (IsSending) XPROGTarget_SetRxMode(); +#if (ARCH == ARCH_AVR8) /* Turn off receiver and transmitter of the USART, clear settings */ UCSR1A |= (1 << TXC1) | (1 << RXC1); UCSR1B = 0; @@ -129,6 +186,23 @@ void XPROGTarget_DisableTargetTPI(void) /* Tristate target /RESET line */ AUX_LINE_DDR &= ~AUX_LINE_MASK; AUX_LINE_PORT &= ~AUX_LINE_MASK; +#elif (ARCH == ARCH_XMEGA) + /* Turn off receiver and transmitter of the USART, clear settings */ + PDI_USART.STATUS = USART_RXCIF_bm | USART_TXCIF_bm; + PDI_USART.CTRLA = 0; + PDI_USART.CTRLB = 0; + PDI_USART.CTRLC = 0; + + /* Tristate all pins */ + PDI_PORT.DIRCLR = PDI_TX_MASK | PDI_XCK_MASK; + PDI_PORT.PDI_XCK_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc | PORT_INVEN_bm); + PDI_PORT.PDI_TX_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc); + PDI_PORT.PDI_RX_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc); + + AUX_LINE_PORT.DIRCLR = AUX_LINE_MASK; + AUX_LINE_PORT.OUTCLR = AUX_LINE_MASK; + AUX_LINE_PORT.AUX_LINE_CTRL &= ~(PORT_OPC_PULLUP_gc | PORT_OPC_PULLDOWN_gc); +#endif } /** Sends a byte via the USART. @@ -142,9 +216,16 @@ void XPROGTarget_SendByte(const uint8_t Byte) XPROGTarget_SetTxMode(); /* Wait until there is space in the hardware Tx buffer before writing */ +#if (ARCH == ARCH_AVR8) while (!(UCSR1A & (1 << UDRE1))); UCSR1A |= (1 << TXC1); UDR1 = Byte; +#elif (ARCH == ARCH_XMEGA) + while(!(PDI_USART.STATUS & USART_DREIF_bm)) + ; + PDI_USART.STATUS |= USART_TXCIF_bm; + PDI_USART.DATA = Byte; +#endif } /** Receives a byte via the hardware USART, blocking until data is received or timeout expired. @@ -158,9 +239,15 @@ uint8_t XPROGTarget_ReceiveByte(void) XPROGTarget_SetRxMode(); /* Wait until a byte has been received before reading */ - while (!(UCSR1A & (1 << RXC1)) && TimeoutTicksRemaining); - +#if (ARCH == ARCH_AVR8) + while (!(UCSR1A & (1 << RXC1)) && TimeoutTicksRemaining) + ; return UDR1; +#elif (ARCH == ARCH_XMEGA) + while(!(PDI_USART.STATUS & USART_RXCIF_bm) && TimeoutTicksRemaining) + ; + return PDI_USART.DATA; +#endif } /** Sends an IDLE via the USART to the attached target, consisting of a full frame of idle bits. */ @@ -173,16 +260,27 @@ void XPROGTarget_SendIdle(void) /* Need to do nothing for a full frame to send an IDLE */ for (uint8_t i = 0; i < BITS_IN_USART_FRAME; i++) { +#if (ARCH == ARCH_AVR8) /* Wait for a full cycle of the clock */ while (PIND & (1 << 5)); while (!(PIND & (1 << 5))); while (PIND & (1 << 5)); +#elif (ARCH == ARCH_XMEGA) + /* As the pin inversion is active we need to wait inverted */ + while (!(PDI_PORT.IN & PDI_XCK_MASK)) + ; + while ((PDI_PORT.IN & PDI_XCK_MASK)) + ; + while (!(PDI_PORT.IN & PDI_XCK_MASK)) + ; +#endif } } static void XPROGTarget_SetTxMode(void) { /* Wait for a full cycle of the clock */ +#if (ARCH == ARCH_AVR8) while (PIND & (1 << 5)); while (!(PIND & (1 << 5))); while (PIND & (1 << 5)); @@ -192,12 +290,26 @@ static void XPROGTarget_SetTxMode(void) UCSR1B &= ~(1 << RXEN1); UCSR1B |= (1 << TXEN1); - +#elif (ARCH == ARCH_XMEGA) + /* As the pin is actived, we need to wait inverted */ + while (!(PDI_PORT.IN & PDI_XCK_MASK)) + ; + while ((PDI_PORT.IN & PDI_XCK_MASK)) + ; + while (!(PDI_PORT.IN & PDI_XCK_MASK)) + ; + + PDI_PORT.OUTSET = PDI_TX_MASK; + PDI_PORT.DIRSET = PDI_TX_MASK; + + PDI_USART.CTRLB = (PDI_USART.CTRLB & ~(USART_TXEN_bm | USART_RXEN_bm)) | USART_TXEN_bm; +#endif IsSending = true; } static void XPROGTarget_SetRxMode(void) { +#if (ARCH == ARCH_AVR8) while (!(UCSR1A & (1 << TXC1))); UCSR1A |= (1 << TXC1); @@ -206,7 +318,16 @@ static void XPROGTarget_SetRxMode(void) DDRD &= ~(1 << 3); PORTD &= ~(1 << 3); +#elif (ARCH == ARCH_XMEGA) + while(!(PDI_USART.STATUS & USART_TXCIF_bm)) + ; + PDI_USART.STATUS = USART_TXCIF_bm; + + PDI_USART.CTRLB = (PDI_USART.CTRLB & ~(USART_TXEN_bm | USART_RXEN_bm)) | USART_RXEN_bm; + PDI_PORT.DIRCLR = PDI_TX_MASK; + PDI_PORT.OUTCLR = PDI_TX_MASK; +#endif IsSending = false; } diff --git a/Projects/AVRISP-MKII/makefile b/Projects/AVRISP-MKII/makefile index 109faad15..cebe7579a 100644 --- a/Projects/AVRISP-MKII/makefile +++ b/Projects/AVRISP-MKII/makefile @@ -11,12 +11,12 @@ # Run "make help" for target help. -MCU = at90usb1287 -ARCH = AVR8 -BOARD = USBKEY -F_CPU = 8000000 -F_USB = $(F_CPU) -OPTIMIZATION = s +MCU = atxmega256a3u +ARCH = XMEGA +BOARD = NONE +F_CPU = 32000000 +F_USB = 48000000 +OPTIMIZATION = 2 TARGET = AVRISP-MKII SRC = $(TARGET).c AVRISPDescriptors.c Lib/V2Protocol.c Lib/V2ProtocolParams.c Lib/ISP/ISPProtocol.c Lib/ISP/ISPTarget.c Lib/XPROG/XPROGProtocol.c \ Lib/XPROG/XPROGTarget.c Lib/XPROG/XMEGANVM.c Lib/XPROG/TINYNVM.c $(LUFA_SRC_USB)