Example #1
0
File: main.c Project: Maelok/esc32
void main(void) {
    rccInit();
    timerInit();
    configInit();
    adcInit();
    fetInit();
    serialInit();
    runInit();
    cliInit();
    owInit();

    runDisarm(REASON_STARTUP);
    inputMode = ESC_INPUT_PWM;

    fetSetDutyCycle(0);
    fetBeep(200, 100);
    fetBeep(300, 100);
    fetBeep(400, 100);
    fetBeep(500, 100);
    fetBeep(400, 100);
    fetBeep(300, 100);
    fetBeep(200, 100);

    pwmInit();

    statusLed = digitalInit(GPIO_STATUS_LED_PORT, GPIO_STATUS_LED_PIN);
    digitalHi(statusLed);
    errorLed = digitalInit(GPIO_ERROR_LED_PORT, GPIO_ERROR_LED_PIN);
    digitalHi(errorLed);
#ifdef ESC_DEBUG
    tp = digitalInit(GPIO_TP_PORT, GPIO_TP_PIN);
    digitalLo(tp);
#endif

    // self calibrating idle timer loop
    {
        volatile unsigned long cycles;
        volatile unsigned int *DWT_CYCCNT = (int *)0xE0001004;
        volatile unsigned int *DWT_CONTROL = (int *)0xE0001000;
        volatile unsigned int *SCB_DEMCR = (int *)0xE000EDFC;

        *SCB_DEMCR = *SCB_DEMCR | 0x01000000;
        *DWT_CONTROL = *DWT_CONTROL | 1;	// enable the counter

	minCycles = 0xffff;
        while (1) {
            idleCounter++;

	    NOPS_4;

            cycles = *DWT_CYCCNT;
            *DWT_CYCCNT = 0;		    // reset the counter

            // record shortest number of instructions for loop
	    totalCycles += cycles;
            if (cycles < minCycles)
                minCycles = cycles;
        }
    }
}
Example #2
0
void rccConfiguration(void) {
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE |
						   RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH,
						   ENABLE);

	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	GPIO_Init(GPIOE, &GPIO_InitStructure);

	// exclude PA13 & PA14 for SWD
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All & ~(GPIO_Pin_13 | GPIO_Pin_14);
	GPIO_Init(GPIOA, &GPIO_InitStructure);

#ifdef RCC_EN1_PORT
	en1 = digitalInit(RCC_EN1_PORT, RCC_EN1_PIN, 1);
#endif
#ifdef RCC_EN2_PORT
	en2 = digitalInit(RCC_EN2_PORT, RCC_EN2_PIN, 0);
#endif
#ifdef RCC_SYSOFF_PORT
	sysoff = digitalInit(RCC_SYSOFF_PORT, RCC_SYSOFF_PIN, 0);
#endif
#ifdef RCC_STEPUP_EN_PORT
	stepupEn = digitalInit(RCC_STEPUP_EN_PORT, RCC_STEPUP_EN_PIN, 1);
#endif
#ifdef RCC_SYNC_PORT
	sync = digitalInit(RCC_SYNC_PORT, RCC_SYNC_PIN, 1);
#endif

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_DMA2, ENABLE);

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	// enable timer clocks
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4 | RCC_APB1Periph_TIM7, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_TIM8 | RCC_APB2Periph_TIM9 | RCC_APB2Periph_TIM10 | RCC_APB2Periph_TIM11,
						   ENABLE);

	SYSCFG_CompensationCellCmd(ENABLE);

	// Clear reset flags
	RCC_ClearFlag();

	RCC_GetClocksFreq(&rccClocks);

	pwmZeroTimers();
}
Example #3
0
static void radioRCSelect(uint8_t rcPort, uint8_t level) {
#ifdef RADIO_RC1_SELECT_PORT
    if (rcPort == 0)
        radioData.select[0] = digitalInit(RADIO_RC1_SELECT_PORT, RADIO_RC1_SELECT_PIN, level);
#endif

#ifdef RADIO_RC2_SELECT_PORT
    if (rcPort == 1)
        radioData.select[1] = digitalInit(RADIO_RC2_SELECT_PORT, RADIO_RC2_SELECT_PIN, level);
#endif
}
Example #4
0
void supervisorInit(void) {
    memset((void *)&supervisorData, 0, sizeof(supervisorData));

    supervisorData.readyLed = digitalInit(SUPERVISOR_READY_PORT, SUPERVISOR_READY_PIN, 0);
#ifdef SUPERVISOR_DEBUG_PORT
    supervisorData.debugLed = digitalInit(SUPERVISOR_DEBUG_PORT, SUPERVISOR_DEBUG_PIN, 0);
#endif
    supervisorData.gpsLed = digitalInit(GPS_LED_PORT, GPS_LED_PIN, 0);

    supervisorData.state = STATE_INITIALIZING;
    supervisorTaskStack = aqStackInit(SUPERVISOR_STACK_SIZE, "SUPERVISOR");

    supervisorData.supervisorTask = CoCreateTask(supervisorTaskCode, (void *)0, SUPERVISOR_PRIORITY, &supervisorTaskStack[SUPERVISOR_STACK_SIZE-1], SUPERVISOR_STACK_SIZE);
}
Example #5
0
spiClient_t *spiClientInit(SPI_TypeDef *spi, uint16_t baud, GPIO_TypeDef *csPort, uint16_t csPin, volatile uint32_t *flag, spiCallback_t *callback) {
    spiClient_t *client;

    client = (spiClient_t *)aqCalloc(1, sizeof(spiClient_t));

#ifdef SPI_SPI1_CLOCK
    if (spi == SPI1) {
	client->interface = 0;
	spi1Init();
    }
#endif
#ifdef SPI_SPI2_CLOCK
    if (spi == SPI2) {
	client->interface = 1;
	spi2Init();
    }
#endif
#ifdef SPI_SPI3_CLOCK
    if (spi == SPI3) {
	client->interface = 2;
	spi3Init();
    }
#endif

    client->cs = digitalInit(csPort, csPin, 1);
    spiDeselect(client);

    spiChangeBaud(client, baud);
    client->flag = flag;
    client->callback = callback;

    return client;
}
Example #6
0
void rccBootLoader(void) {
    // check for magic cookie
    if (rccReadBkpDr() == 0xDECEA5ED) {
        digitalPin *statusLed, *errorLed;

        rccWriteBkpDr(0); // reset flag

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

        statusLed = digitalInit(GPIO_STATUS_LED_PORT, GPIO_STATUS_LED_PIN);
        digitalLo(statusLed);
        errorLed = digitalInit(GPIO_ERROR_LED_PORT, GPIO_ERROR_LED_PIN);
        digitalLo(errorLed);

        // jump to boot loader ROM
        __asm volatile ("LDR     R0, =0x1FFFF000\n"
                        "LDR     SP,[R0, #0]\n"
                        "LDR     R0,[R0, #4]\n"
                        "BX      R0\n");
    }
Example #7
0
void adcInit(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    AQ_NOTICE("ADC init\n");

    memset((void *)&adcData, 0, sizeof(adcData));

    // energize mag's set/reset circuit
    adcData.magSetReset = digitalInit(GPIOE, GPIO_Pin_10, 1);

    // use auto-zero function of gyros
    adcData.rateAutoZero = digitalInit(GPIOE, GPIO_Pin_8, 0);

    // bring ACC's SELF TEST line low
    adcData.accST = digitalInit(GPIOE, GPIO_Pin_12, 0);

    // bring ACC's SCALE line low (ADXL3X5 requires this line be tied to GND or left floating)
    adcData.accScale = digitalInit(GPIOC, GPIO_Pin_15, 0);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);

    adcData.sample = ADC_SAMPLES - 1;

    // Use STM32F4's Triple Regular Simultaneous Mode capable of ~ 6M samples per second

    DMA_DeInit(ADC_DMA_STREAM);
    DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adcDMAData.adc123Raw1;
    DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)0x40012308);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = ADC_CHANNELS * 3 * 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure);

    DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_HT | DMA_IT_TC, ENABLE);
    DMA_ClearITPendingBit(ADC_DMA_STREAM, ADC_DMA_FLAGS);

    DMA_Cmd(ADC_DMA_STREAM, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = ADC_DMA_IRQ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // ADC Common Init
    ADC_CommonStructInit(&ADC_CommonInitStructure);
    ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
    ADC_CommonInit(&ADC_CommonInitStructure);

    // ADC1 configuration
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 16;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGX, 1, ADC_SAMPLE_TIME);	// magX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGX, 2, ADC_SAMPLE_TIME);	// magX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGX, 3, ADC_SAMPLE_TIME);	// magX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGX, 4, ADC_SAMPLE_TIME);	// magX

    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGY, 5, ADC_SAMPLE_TIME);	// magY
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGY, 6, ADC_SAMPLE_TIME);	// magY
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGY, 7, ADC_SAMPLE_TIME);	// magY
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGY, 8, ADC_SAMPLE_TIME);	// magY

    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGZ, 9, ADC_SAMPLE_TIME);	// magZ
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGZ, 10, ADC_SAMPLE_TIME);	// magZ
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGZ, 11, ADC_SAMPLE_TIME);	// magZ
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_MAGZ, 12, ADC_SAMPLE_TIME);	// magZ

    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_RATEX, 13, ADC_SAMPLE_TIME);	// rateX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_RATEX, 14, ADC_SAMPLE_TIME);	// rateX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_RATEX, 15, ADC_SAMPLE_TIME);	// rateX
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_RATEX, 16, ADC_SAMPLE_TIME);	// rateX

    // Enable ADC1 DMA since ADC1 is the Master
    ADC_DMACmd(ADC1, ENABLE);

    // ADC2 configuration
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 16;
    ADC_Init(ADC2, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_RATEY, 1, ADC_SAMPLE_TIME);	// rateY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_RATEY, 2, ADC_SAMPLE_TIME);	// rateY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_RATEY, 3, ADC_SAMPLE_TIME);	// rateY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_RATEY, 4, ADC_SAMPLE_TIME);	// rateY

    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCX, 5, ADC_SAMPLE_TIME);	// accX
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCX, 6, ADC_SAMPLE_TIME);	// accX
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCX, 7, ADC_SAMPLE_TIME);	// accX
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCX, 8, ADC_SAMPLE_TIME);	// accX

    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCY, 9, ADC_SAMPLE_TIME);	// accY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCY, 10, ADC_SAMPLE_TIME);	// accY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCY, 11, ADC_SAMPLE_TIME);	// accY
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCY, 12, ADC_SAMPLE_TIME);	// accY

    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCZ, 13, ADC_SAMPLE_TIME);	// accZ
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCZ, 14, ADC_SAMPLE_TIME);	// accZ
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCZ, 15, ADC_SAMPLE_TIME);	// accZ
    ADC_RegularChannelConfig(ADC2, ADC_CHANNEL_ACCZ, 16, ADC_SAMPLE_TIME);	// accZ

    // ADC3 configuration
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 16;
    ADC_Init(ADC3, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_RATEZ, 1, ADC_SAMPLE_TIME);	// rateZ
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_RATEZ, 2, ADC_SAMPLE_TIME);	// rateZ
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_RATEZ, 3, ADC_SAMPLE_TIME);	// rateZ
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_RATEZ, 4, ADC_SAMPLE_TIME);	// rateZ

    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_TEMP1, 5, ADC_SAMPLE_TIME);	// temp1
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_TEMP2, 6, ADC_SAMPLE_TIME);	// temp2

    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES1, 7, ADC_SAMPLE_TIME);	// pressure1
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES1, 8, ADC_SAMPLE_TIME);	// pressure1
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES1, 9, ADC_SAMPLE_TIME);	// pressure1
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES1, 10, ADC_SAMPLE_TIME);	// pressure1

    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_VIN, 11, ADC_SAMPLE_TIME);	// Vin
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_TEMP3, 12, ADC_SAMPLE_TIME);	// temp3

    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES2, 13, ADC_SAMPLE_TIME);	// pressure2
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES2, 14, ADC_SAMPLE_TIME);	// pressure2
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES2, 15, ADC_SAMPLE_TIME);	// pressure2
    ADC_RegularChannelConfig(ADC3, ADC_CHANNEL_PRES2, 16, ADC_SAMPLE_TIME);	// pressure2

    // Enable DMA request after last transfer (Multi-ADC mode)
    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

    // Enable
    ADC_Cmd(ADC1, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    ADC_Cmd(ADC3, ENABLE);

    adcData.adcFlag = CoCreateFlag(1, 0);
    adcTaskStack = aqStackInit(ADC_STACK_SIZE, "ADC");

    adcData.adcTask = CoCreateTask(adcTaskCode, (void *)0, ADC_PRIORITY, &adcTaskStack[ADC_STACK_SIZE-1], ADC_STACK_SIZE);

    // Start ADC1 Software Conversion
    ADC_SoftwareStartConv(ADC1);

    yield(100);

    // set initial temperatures
    adcData.temp1 = adcIDGVoltsToTemp(adcData.voltages[ADC_VOLTS_TEMP1]);
    adcData.temp2 = adcIDGVoltsToTemp(adcData.voltages[ADC_VOLTS_TEMP2]);
    adcData.temp3 = adcT1VoltsToTemp(adcData.voltages[ADC_VOLTS_TEMP3]);
    analogData.vIn = adcVsenseToVin(adcData.voltages[ADC_VOLTS_VIN]);

    adcCalibOffsets();
}
Example #8
0
void main(void) {
    rccInit();

    statusLed = digitalInit(GPIO_STATUS_LED_PORT, GPIO_STATUS_LED_PIN);
    errorLed = digitalInit(GPIO_ERROR_LED_PORT, GPIO_ERROR_LED_PIN);
#ifdef ESC_DEBUG
    tp = digitalInit(GPIO_TP_PORT, GPIO_TP_PIN);
    digitalLo(tp);
#endif

    timerInit();
    configInit();
    adcInit();
    fetInit();
    serialInit();
    canInit();
    runInit();
    cliInit();
    owInit();

    runDisarm(REASON_STARTUP);
    inputMode = ESC_INPUT_PWM;

    fetSetDutyCycle(0);
    fetBeep(200, 100);
    fetBeep(300, 100);
    fetBeep(400, 100);
    fetBeep(500, 100);
    fetBeep(400, 100);
    fetBeep(300, 100);
    fetBeep(200, 100);

    pwmInit();

    digitalHi(statusLed);
    digitalHi(errorLed);

    // self calibrating idle timer loop
    {
	uint32_t lastRunCount;
	uint32_t thisCycles, lastCycles;
        volatile uint32_t cycles;
        volatile uint32_t *DWT_CYCCNT = (uint32_t *)0xE0001004;
        volatile uint32_t *DWT_CONTROL = (uint32_t *)0xE0001000;
        volatile uint32_t *SCB_DEMCR = (uint32_t *)0xE000EDFC;

        *SCB_DEMCR = *SCB_DEMCR | 0x01000000;
        *DWT_CONTROL = *DWT_CONTROL | 1;	// enable the counter

	minCycles = 0xffff;
        while (1) {
            idleCounter++;

	    if (runCount != lastRunCount && !(runCount % (RUN_FREQ / 1000))) {
		if (commandMode == CLI_MODE)
		    cliCheck();
		else
		    binaryCheck();
		lastRunCount = runCount;
	    }

            thisCycles = *DWT_CYCCNT;
	    cycles = thisCycles - lastCycles;
	    lastCycles = thisCycles;

            // record shortest number of instructions for loop
	    totalCycles += cycles;
            if (cycles < minCycles)
                minCycles = cycles;
        }
    }
}