From 2f70bf7ac764b7971987ceb15c1fb17b8e46915c Mon Sep 17 00:00:00 2001 From: jacobseptember Date: Mon, 3 Dec 2018 10:17:22 -0500 Subject: Add support for RC calibration from AVR053 --- Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c | 116 +++++++++++++++++++++++++---- Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.h | 1 + 2 files changed, 102 insertions(+), 15 deletions(-) diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c index 0ece159a6..870bb188f 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c @@ -1,14 +1,16 @@ /* - LUFA Library - Copyright (C) Dean Camera, 2018. + LUFA Library + Copyright (C) Dean Camera, 2018. dean [at] fourwalledcubicle [dot] com - www.lufa-lib.org + www.lufa-lib.org */ /* Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Function ISProtocol_Calibrate() copyright 2018 Jacob September + Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in @@ -145,10 +147,10 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) uint8_t PollValue1; uint8_t PollValue2; uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the - } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting + } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) - - sizeof(Write_Memory_Params.ProgData)), NULL); + sizeof(Write_Memory_Params.ProgData)), NULL); Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite); if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData)) @@ -168,7 +170,7 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) // The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need // to catch this and discard it before continuing on with packet processing to prevent communication issues if (((sizeof(uint8_t) + sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData)) + - Write_Memory_Params.BytesToWrite) % AVRISP_DATA_EPSIZE == 0) + Write_Memory_Params.BytesToWrite) % AVRISP_DATA_EPSIZE == 0) { Endpoint_ClearOUT(); Endpoint_WaitUntilReady(); @@ -179,15 +181,15 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ProgrammingStatus = STATUS_CMD_OK; - uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 : - Write_Memory_Params.PollValue2; - uint16_t PollAddress = 0; - uint8_t* NextWriteByte = Write_Memory_Params.ProgData; + uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 : + Write_Memory_Params.PollValue2; + uint16_t PollAddress = 0; + uint8_t* NextWriteByte = Write_Memory_Params.ProgData; uint16_t PageStartAddress = (CurrentAddress & 0xFFFF); for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++) { - uint8_t ByteToWrite = *(NextWriteByte++); + uint8_t ByteToWrite = *(NextWriteByte++); uint8_t ProgrammingMode = Write_Memory_Params.ProgrammingMode; /* Check to see if we need to send a LOAD EXTENDED ADDRESS command to the target */ @@ -226,8 +228,8 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) ProgrammingMode = (ProgrammingMode & ~PROG_MODE_WORD_VALUE_MASK) | PROG_MODE_WORD_TIMEDELAY_MASK; ProgrammingStatus = ISPTarget_WaitForProgComplete(ProgrammingMode, PollAddress, PollValue, - Write_Memory_Params.DelayMS, - Write_Memory_Params.ProgrammingCommands[2]); + Write_Memory_Params.DelayMS, + Write_Memory_Params.ProgrammingCommands[2]); /* Abort the programming loop early if the byte/word programming failed */ if (ProgrammingStatus != STATUS_CMD_OK) @@ -265,8 +267,8 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) } ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue, - Write_Memory_Params.DelayMS, - Write_Memory_Params.ProgrammingCommands[2]); + Write_Memory_Params.DelayMS, + Write_Memory_Params.ProgrammingCommands[2]); /* Check to see if the FLASH address has crossed the extended address boundary */ if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF)) @@ -388,6 +390,89 @@ void ISPProtocol_ChipErase(void) Endpoint_ClearIN(); } +/** Global volatile variables used in ISRs relating to ISPProtocol_Calibrate() */ +volatile uint16_t HalfCyclesRemaining; +volatile uint8_t ResponseTogglesRemaining; + +/** ISR to toggle MOSI pin when TIMER1 overflows */ +ISR(TIMER1_OVF_vect) +{ + PINB |= (1 << PB2); // toggle PB2 (MOSI) by writing 1 to its bit in PINB + HalfCyclesRemaining--; +} + +/** ISR to listen for toggles on MISO pin */ +ISR(PCINT0_vect) +{ + ResponseTogglesRemaining--; +} + +/** Handler for the CMD_OSCCAL command, entering RC-calibration mode as specified in AVR053 */ +void ISPProtocol_Calibrate(void) +{ + #define CALIB_CLOCK 32768 + // CALIB_TICKS uses 2x frequency because we toggle twice per cycle + // and adds 1/2 denom. to nom. to ensure rounding instead of flooring of integer division + #define CALIB_TICKS ( (F_CPU+CALIB_CLOCK) / (2*CALIB_CLOCK) ) + // Per AVR053, calibration guaranteed to take 1024 cycles (2048 half-cycles) or fewer; + // add some cycles for response delay (5-10 after success) and response itself + #define HALF_CYCLE_LIMIT (2*1024 + 50) + #define SUCCESS_TOGGLE_NUM 8 + + uint8_t ResponseStatus = STATUS_CMD_OK; + + /* Don't entirely know why this is needed, something to do with the USB communication back to PC */ + Endpoint_ClearOUT(); + Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); + Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); + + /* Enable pullup on MISO and release ~RESET */ + DDRB = ~(1 << PB3); // explicitly set all PORTB to outputs except PB3 (MISO) + PORTB |= ( (1 << PB4) | (1 << PB3) ); // set PB4 (TARG_RST) high (i.e. not reset) and enable pullup on PB3 (MISO) + + /* Set up MISO pin (PCINT3) to listen for toggles */ + PCMSK0 = (1 << PCINT3); // set mask to enable PCINT on only Pin 3 (MISO) + + /* Set up timer that fires at a rate of 65536 Hz - this will drive the MOSI toggle */ + OCR1A = CALIB_TICKS - 1; // zero-indexed counter; for 16MHz system clock, this becomes 243 + TCCR1A = ( (1 << WGM11) | (1 << WGM10) ); // set for fast PWM, TOP = OCR1A + TCCR1B = ( (1 << WGM13) | (1 << WGM12) | (1 << CS10) ); // ... and no clock prescaling + TCNT1 = 0; // reset counter + + /* Initialize counter variables */ + HalfCyclesRemaining = HALF_CYCLE_LIMIT; + ResponseTogglesRemaining = SUCCESS_TOGGLE_NUM; + + /* Turn on interrupts */ + uint8_t OldSREG = SREG; // save current global interrupt state + PCICR |= (1 << PCIE0); // enable interrupts for PCINT7:0 (don't touch setting for PCINT12:8) + TIMSK1 = (1 << TOIE1); // enable T1 OVF interrupt (and no other T1 interrupts) + sei(); // enable global interrupts + + /* Let device do its calibration, wait for reponse on MISO */ + while ( HalfCyclesRemaining && ResponseTogglesRemaining ) + { + // do nothing... + } + + /* Disable interrupts, restore SREG */ + PCICR &= ~(1 << PCIE0); + TIMSK1 = 0; + SREG = OldSREG; + + /* Check if device responded with a success message or if we timed out */ + if (ResponseTogglesRemaining) + { + ResponseStatus = STATUS_CMD_TOUT; + } + + /* Report back to PC via USB */ + Endpoint_Write_8(CMD_OSCCAL); + Endpoint_Write_8(ResponseStatus); + Endpoint_ClearIN(); + +} // void ISPProtocol_Calibrate(void) + /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands, * reading the requested configuration byte from the device. * @@ -527,5 +612,6 @@ void ISPProtocol_DelayMS(uint8_t DelayMS) Delay_MS(1); } + #endif diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.h b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.h index ae2384a9b..7bf2ff7b5 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.h +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.h @@ -73,6 +73,7 @@ void ISPProtocol_ProgramMemory(const uint8_t V2Command); void ISPProtocol_ReadMemory(const uint8_t V2Command); void ISPProtocol_ChipErase(void); + void ISPProtocol_Calibrate(void); void ISPProtocol_ReadFuseLockSigOSCCAL(const uint8_t V2Command); void ISPProtocol_WriteFuseLock(const uint8_t V2Command); void ISPProtocol_SPIMulti(void); -- cgit v1.2.3