//! Configures the ICSCG target clock //! //! @param busFrequency - Resulting BDM frequency after clock adjustment //! @param clockParameters - Describes clock settings to use //! //! @return error code, see \ref USBDM_ErrorCode //! //! @note Assumes that connection with the target has been established so //! reports any errors as PROGRAMMING_RC_ERROR_FAILED_CLOCK indicating //! a problem programming the target clock. //! USBDM_ErrorCode FlashProgrammer::configureICS_Clock(unsigned long *busFrequency, ICS_ClockParameters_t *clockParameters){ LOGGING_E; const uint32_t ICSC1 = parameters.getClockAddress(); const uint32_t ICSC2 = parameters.getClockAddress()+1; const uint32_t ICSTRIM = parameters.getClockAddress()+2; const uint32_t ICSSC = parameters.getClockAddress()+3; unsigned long bdmFrequency; Logging::print("ICS Clock: Ad=0x%08X, C1=0x%02X, C2=0x%02X, SC=0x%02X\n", parameters.getClockAddress(), clockParameters->icsC1, clockParameters->icsC2, clockParameters->icsSC ); flashReady = FALSE; // Not configured for Flash access // ToDo - Review order of writes & need for re-connect() if (writeClockRegister(ICSTRIM, clockParameters->icsTrim) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_Connect() != BDM_RC_OK) {// re-connect after possible bus speed change return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(ICSC1, clockParameters->icsC1) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(ICSC2, clockParameters->icsC2) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_Connect() != BDM_RC_OK) { // re-connect after possible bus speed change - no delay return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(ICSSC, clockParameters->icsSC) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } milliSleep(100); if (USBDM_Connect() != BDM_RC_OK) { // re-connect after possible FLL change return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_GetSpeed(&bdmFrequency) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } bdmFrequency *= 1000; // Convert to Hz *busFrequency = bdmFrequency*parameters.getBDMtoBUSFactor(); Logging::print("BDM Speed = %ld kHz, Bus Speed = %ld kHz\n", bdmFrequency/1000, *busFrequency/1000); return PROGRAMMING_RC_OK; }
//! Resets the target to normal or special mode //! //! @param target_mode see \ref target_mode_e //! //! @return 0 => Success,\n !=0 => Fail //! TBDML_API unsigned char _tbdml_target_reset(TargetMode_t targetMode) { USBDM_ErrorCode rc; rc = USBDM_TargetReset(targetMode); // Automatically connect after a reset if (rc == BDM_RC_OK) rc = USBDM_Connect(); return rc; }
//! Clock register write with retry //! //! @param addr : clock register address //! @param data : byte to write //! //! @return BDM_RC_OK => success //! //! @note writes are retried after a re-connect to cope //! with a possible clock speed change. //! USBDM_ErrorCode writeClockRegister(uint32_t addr, uint8_t data) { LOGGING_Q; USBDM_ErrorCode rc; rc = USBDM_WriteMemory(1,1,addr,&data); if (rc != BDM_RC_OK) { Logging::print("Failed write 0x%04X <= 0x%02X) - retrying\n", addr, data); rc = USBDM_Connect(); if (rc == BDM_RC_OK) { rc = USBDM_WriteMemory(1,1,addr,&data); if (rc != BDM_RC_OK) { } } } if (rc != BDM_RC_OK) { Logging::print("Failed write 0x%04X <= 0x%02X), rc = %s\n", addr, data, USBDM_GetErrorString(rc)); } return rc; }
//! Configures the External target clock //! //! @param busFrequency - Resulting BDM frequency after clock adjustment (Hz) //! //! @return error code, see \ref USBDM_ErrorCode //! USBDM_ErrorCode FlashProgrammer::configureExternal_Clock(unsigned long *busFrequency){ LOGGING_E; unsigned long bdmFrequency; flashReady = FALSE; // Not configured for Flash access // Just connect at whatever speed if (USBDM_Connect() != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } if (USBDM_GetSpeed(&bdmFrequency) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } bdmFrequency *= 1000; // Convert to Hz *busFrequency = bdmFrequency*parameters.getBDMtoBUSFactor(); Logging::print("BDM Speed = %ld kHz, Bus Speed = %ld kHz\n", bdmFrequency/1000, *busFrequency/1000); return PROGRAMMING_RC_OK; }
USBDM_ErrorCode usbdmInit(TargetType_t targetType = T_CFV1) { unsigned int deviceCount; unsigned int deviceNum; USBDM_ErrorCode rc = USBDM_Init(); if (rc != BDM_RC_OK) { return rc; } rc = USBDM_FindDevices(&deviceCount); print( "usbdmInit(): Usb initialised, found %d device(s)\n", deviceCount); print("After USBDM_FindDevices, Time = %f\n", progressTimer->elapsedTime()); if (rc != BDM_RC_OK) { return rc; } deviceNum = 0; rc = USBDM_Open(deviceNum); if (rc != BDM_RC_OK) { print( "usbdmInit(): Failed to open %s, device #%d\n", getTargetTypeName(targetType), deviceNum); return rc; } print( "usbdmInit(): Opened %s, device #%d\n", getTargetTypeName(targetType), deviceNum); print("After USBDM_Open, Time = %f\n", progressTimer->elapsedTime()); // Set up sensible default since we can't change this (at the moment) USBDM_ExtendedOptions_t bdmOptions = {sizeof(USBDM_ExtendedOptions_t), TARGET_TYPE}; USBDM_GetDefaultExtendedOptions(&bdmOptions); bdmOptions.targetVdd = BDM_TARGET_VDD_3V3; // BDM_TARGET_VDD_NONE; bdmOptions.autoReconnect = AUTOCONNECT_ALWAYS; // Aggressively auto-connect bdmOptions.guessSpeed = FALSE; bdmOptions.cycleVddOnConnect = FALSE; bdmOptions.cycleVddOnReset = FALSE; bdmOptions.leaveTargetPowered = FALSE; bdmOptions.bdmClockSource = CS_DEFAULT; bdmOptions.useResetSignal = FALSE; bdmOptions.usePSTSignals = FALSE; bdmOptions.interfaceFrequency = 1000; // 1MHz bdmOptions.powerOnRecoveryInterval = 100; bdmOptions.resetDuration = 100; bdmOptions.resetReleaseInterval = 100; bdmOptions.resetRecoveryInterval = 100; rc = USBDM_SetExtendedOptions(&bdmOptions); if (rc != BDM_RC_OK) { print( "usbdmInit(): USBDM_SetExtendedOptions() failed\n"); return rc; } print("After USBDM_SetExtendedOptions, Time = %f\n", progressTimer->elapsedTime()); rc = USBDM_SetTargetType(targetType); if (rc != BDM_RC_OK) { print( "usbdmInit(): USBDM_SetTargetType() failed\n"); return rc; } print("After USBDM_SetTargetType, Time = %f\n", progressTimer->elapsedTime()); USBDM_TargetReset((TargetMode_t)(RESET_DEFAULT|RESET_SPECIAL)); print("After USBDM_TargetReset, Time = %f\n", progressTimer->elapsedTime()); if (USBDM_Connect() != BDM_RC_OK) { print( "usbdmInit(): Connecting failed - retry\n"); USBDM_TargetReset((TargetMode_t)(RESET_DEFAULT|RESET_SPECIAL)); rc = USBDM_Connect(); if (rc != BDM_RC_OK) { print( "targetConnect(): USBDM_SetTargetType() failed\n"); return rc; } } print("After targetConnect, Time = %f\n", progressTimer->elapsedTime()); return BDM_RC_OK; }
//! Determines the trim value for the target internal clock. //! The target clock is left trimmed for a bus freq. of targetBusFrequency. //! //! Target clock has been suitably configured. //! //! @param trimAddress Address of trim register. //! @param targetBusFrequency Target Bus Frequency to trim to. //! @param returnTrimValue Resulting trim value (9-bit number) //! @param measuredBusFrequency Resulting Bus Frequency //! @param do9BitTrim True to do 9-bit trim (rather than 8-bit) //! //! @return //! == \ref PROGRAMMING_RC_OK => Success \n //! != \ref PROGRAMMING_RC_OK => Various errors //! USBDM_ErrorCode FlashProgrammer::trimTargetClock(uint32_t trimAddress, unsigned long targetBusFrequency, uint16_t *returnTrimValue, unsigned long *measuredBusFrequency, int do9BitTrim){ LOGGING; uint8_t mask; uint8_t trimMSB, trimLSB, trimCheck; int trimValue; int maxRange; int minRange; unsigned long bdmSpeed; int index; USBDM_ErrorCode rc = PROGRAMMING_RC_OK; #if TARGET == RS08 mask = RS08_BDCSCR_CLKSW; #elif TARGET == HCS08 mask = HC08_BDCSCR_CLKSW; #elif TARGET == HCS12 mask = HC12_BDMSTS_CLKSW; #elif TARGET == CFV1 mask = CFV1_XCSR_CLKSW; #endif unsigned long BDMStatusReg; rc = USBDM_ReadStatusReg(&BDMStatusReg); if ((BDMStatusReg&mask) == 0) { Logging::print("Setting CLKSW\n"); BDMStatusReg |= mask; #if TARGET == CFV1 // Make sure we don't accidently do a mass erase mask &= ~CFV1_XCSR_ERASE; #endif rc = USBDM_WriteControlReg(BDMStatusReg); rc = USBDM_Connect(); } static const int maxTrim = 505; // Maximum acceptable trim value static const int minTrim = 5; // Minimum acceptable trim value static const int SearchOffset = 8; // Linear sweep range is +/- this value static const unsigned char zero = 0; const unsigned long targetBDMFrequency = targetBusFrequency/parameters.getBDMtoBUSFactor(); int numAverage; // Number of times to repeat measurements double sumX = 0.0; double sumY = 0.0; double sumXX = 0.0; double sumYY = 0.0; double sumXY = 0.0; double num = 0.0; double alpha, beta; double trimValueF; Logging::print("targetBusFrequency=%ld, targetBDMFrequency=%ld)\n", targetBusFrequency, targetBDMFrequency); flashReady = FALSE; // Not configured for Flash access // Set safe defaults *returnTrimValue = 256; *measuredBusFrequency = 10000; trimMSB = 0; // Set LSB trim value = 0 if (writeClockRegister(trimAddress+1, zero) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } // Initial binary search (MSB only) for (mask = 0x80; mask > 0x0; mask>>=1) { trimMSB |= mask; // Set trim value (MSB only) if (writeClockRegister(trimAddress, trimMSB) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } // Check target speed if (USBDM_Connect() != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } if (USBDM_GetSpeed(&bdmSpeed) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } bdmSpeed *= 1000; // convert to Hz Logging::print("Binary search: trimMSB=0x%02X (%d), bdmSpeed=%ld%c\n", trimMSB, trimMSB, bdmSpeed, (bdmSpeed<targetBDMFrequency)?'-':'+'); // Adjust trim value if (bdmSpeed<targetBDMFrequency) { trimMSB &= ~mask; // too slow } if (trimMSB > maxTrim/2) { trimMSB = maxTrim/2; } if (trimMSB < minTrim/2) { trimMSB = minTrim/2; } } // Binary search value is middle of range to sweep trimValue = trimMSB<<1; // Convert to 9-bit value // Linear sweep +/-SEARCH_OFFSET, starting at higher freq (smaller Trim) // Range is constrained to [minTrim..maxTrim] maxRange = trimValue + SearchOffset; if (maxRange > maxTrim) { maxRange = maxTrim; } minRange = trimValue - SearchOffset; if (minRange < minTrim) { minRange = minTrim; } // Logging::print("trimTargetClock(): Linear sweep, f=%6ld \n" // "trimTargetClock(): Trim frequency \n" // "========================================== \n", // targetBDMFrequency/1000); if (do9BitTrim) { numAverage = 2; } else { numAverage = 4; } for(trimValue=maxRange; trimValue>=minRange; trimValue--) { trimLSB = trimValue&0x01; trimMSB = (uint8_t)(trimValue>>1); if (do9BitTrim) { // Write trim LSB if (writeClockRegister(trimAddress+1, trimLSB) != BDM_RC_OK) return PROGRAMMING_RC_ERROR_BDM_WRITE; if (USBDM_ReadMemory(1, 1, trimAddress+1, &trimCheck) != BDM_RC_OK) return PROGRAMMING_RC_ERROR_BDM_WRITE; if ((trimCheck&0x01) != trimLSB) return PROGRAMMING_RC_ERROR_BDM_WRITE; } else if (trimValue&0x01) { // skip odd trim values if 8-bit trim continue; } // Write trim MSB if (writeClockRegister(trimAddress, trimMSB) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if (USBDM_ReadMemory(1, 1, trimAddress, &trimCheck) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if (trimCheck != trimMSB) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } //milliSleep(100); // Measure sync multiple times for(index=numAverage; index>0; index--) { // Check target speed if (USBDM_Connect() != BDM_RC_OK) return PROGRAMMING_RC_ERROR_BDM_CONNECT; if (USBDM_GetSpeedHz(&bdmSpeed) != BDM_RC_OK) return PROGRAMMING_RC_ERROR_BDM_CONNECT; sumX += trimValue; sumY += bdmSpeed; sumXX += trimValue*trimValue; sumYY += bdmSpeed*bdmSpeed; sumXY += bdmSpeed*trimValue; num += 1.0; // Logging::print("trimTargetClock(): %6d %10ld %10ld\n", trimValue, bdmSpeed, targetBDMFrequency-bdmSpeed); } } for(trimValue=minRange; trimValue<=maxRange; trimValue++) { trimLSB = trimValue&0x01; trimMSB = (uint8_t)(trimValue>>1); if (do9BitTrim) { // Write trim LSB if (writeClockRegister(trimAddress+1, trimLSB) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if (USBDM_ReadMemory(1, 1, trimAddress+1, &trimCheck) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if ((trimCheck&0x01) != trimLSB) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } } else if (trimValue&0x01) { // skip odd trim values if 8-bit trim continue; } // Write trim MSB if (writeClockRegister(trimAddress, trimMSB) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if (USBDM_ReadMemory(1, 1, trimAddress, &trimCheck) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } if (trimCheck != trimMSB) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } //milliSleep(100); // Measure sync multiple times for(index=numAverage; index>0; index--) { // Check target speed if (USBDM_Connect() != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } if (USBDM_GetSpeedHz(&bdmSpeed) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } sumX += trimValue; sumY += bdmSpeed; sumXX += trimValue*trimValue; sumYY += bdmSpeed*bdmSpeed; sumXY += bdmSpeed*trimValue; num += 1.0; // Logging::print("trimTargetClock(): %6d %10ld %10ld\n", trimValue, bdmSpeed, targetBDMFrequency-bdmSpeed); } } // Logging::print("N=%f, sumX=%f, sumXX=%f, sumY=%f, sumYY=%f, sumXY=%f\n", // num, sumX, sumXX, sumY, sumYY, sumXY); // Calculate linear regression co-efficients beta = (num*sumXY-sumX*sumY)/(num*sumXX-sumX*sumX); alpha = (sumY-beta*sumX)/num; // Estimate required trim value trimValueF = ((targetBDMFrequency-alpha)/beta); if ((trimValueF <= 5.0) || (trimValue >= 505.0)) { // resulted in extreme value trimValueF = 256.0; // replace with 'Safe' trim value rc = PROGRAMMING_RC_ERROR_TRIM; } trimValue = (int)round(trimValueF); trimMSB = trimValue>>1; trimLSB = trimValue&0x01; // Logging::print("alpha= %f, beta= %f, trimF= %f, trimMSB= %d (0x%02X), trimLSB= %d\n", // alpha, beta, trimValueF, trimMSB, trimMSB, trimLSB); // Logging::print("trimTargetClock() Result: trim=0x%3.3x (%d), measured bdmSpeed=%ld\n", // savedTrimValue, savedTrimValue, bestFrequency); *returnTrimValue = trimValue; // Set trim value (LSB first) if ((do9BitTrim && (writeClockRegister(trimAddress+1, trimLSB) != BDM_RC_OK)) || (writeClockRegister(trimAddress, trimMSB) != BDM_RC_OK)) { return PROGRAMMING_RC_ERROR_BDM_WRITE; } // Check connection at that speed if (USBDM_Connect() != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } if (USBDM_GetSpeedHz(&bdmSpeed) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_BDM_CONNECT; } *measuredBusFrequency = bdmSpeed*parameters.getBDMtoBUSFactor(); return rc; }
//! Configures the MCGCG target clock //! //! @param busFrequency - Resulting BDM frequency after clock adjustment //! @param clockParameters - Describes clock settings to use //! //! @return error code, see \ref USBDM_ErrorCode //! //! @note Assumes that connection with the target has been established so //! reports any errors as PROGRAMMING_RC_ERROR_FAILED_CLOCK indicating //! a problem programming the target clock. //! USBDM_ErrorCode FlashProgrammer::configureMCG_Clock(unsigned long *busFrequency, MCG_ClockParameters_t *clockParameters){ LOGGING_E; const uint32_t MCGC1 = parameters.getClockAddress(); const uint32_t MCGC2 = parameters.getClockAddress()+1; const uint32_t MCGTRIM = parameters.getClockAddress()+2; const uint32_t MCGSC = parameters.getClockAddress()+3; const uint32_t MCGC3 = parameters.getClockAddress()+4; const uint32_t MCGT = parameters.getClockAddress()+5; unsigned long bdmFrequency; Logging::print("MCG Clock: Ad=0x%08X, C1=0x%02X, C2=0x%02X, C3=0x%02X, SC=0x%02X, CT/C4=0x%02X\n", parameters.getClockAddress(), clockParameters->mcgC1, clockParameters->mcgC2, clockParameters->mcgC3, clockParameters->mcgSC, clockParameters->mcgCT ); flashReady = FALSE; // Not configured for Flash access // ToDo - Review order of writes & need for re-connect() if (writeClockRegister(MCGTRIM, clockParameters->mcgTrim) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_Connect() != BDM_RC_OK) { // re-connect after possible bus speed change return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(MCGC1, clockParameters->mcgC1) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(MCGSC, clockParameters->mcgSC) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(MCGC2, clockParameters->mcgC2) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_Connect() != BDM_RC_OK) { // re-connect after possible bus speed change return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (writeClockRegister(MCGC3, clockParameters->mcgC3) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if ((parameters.getClockType() != S08MCGV1) && (writeClockRegister(MCGT, clockParameters->mcgCT) != BDM_RC_OK)) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } milliSleep(100); if (USBDM_Connect() != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } if (USBDM_GetSpeed(&bdmFrequency) != BDM_RC_OK) { return PROGRAMMING_RC_ERROR_FAILED_CLOCK; } bdmFrequency *= 1000; // Convert to Hz *busFrequency = bdmFrequency*parameters.getBDMtoBUSFactor(); Logging::print("BDM Speed = %ld kHz, Bus Speed = %ld kHz\n", bdmFrequency/1000, *busFrequency/1000); return PROGRAMMING_RC_OK; }