LPC824微控制器ADC演示HardFault问题

时间:2018-12-17 00:31:37

标签: embedded clang adc nxp-microcontroller

我正在尝试使用 LPCOpen LPC824 微控制器板([https://www.switch-science.com/catalog/2265/][1])进行编程。 我正在LPCLink 2调试器板上使用它。

我的目标是使用ADC从“压力传感器”中获取一些信息。

当执行 NVIC_EnableIRQ 函数(第92行)时,我的代码以 HardFault 停止。

如果我不使用“ NVIC中断控制器”,那么我的代码可以工作,并且可以使用ADC从传感器获取值。

我做错了什么?

这是我的adc.c代码:

#include "board.h"

static volatile int ticks;
static bool sequenceComplete = false;
static bool thresholdCrossed = false;

#define TICKRATE_HZ (100)     /* 100 ticks per second */

#define BOARD_ADC_CH 2

/**
 * @brief     Handle interrupt from ADC sequencer A
 * @return     Nothing
 */
void ADC_SEQA_IRQHandler(void) {
    uint32_t pending;

    /* Get pending interrupts */
    pending = Chip_ADC_GetFlags(LPC_ADC);

    /* Sequence A completion interrupt */
    if (pending & ADC_FLAGS_SEQA_INT_MASK) {
        sequenceComplete = true;
    }

    /* Threshold crossing interrupt on ADC input channel */
    if (pending & ADC_FLAGS_THCMP_MASK(BOARD_ADC_CH)) {
        thresholdCrossed = true;
    }

    /* Clear any pending interrupts */
    Chip_ADC_ClearFlags(LPC_ADC, pending);
}

/**
 * @brief     Handle interrupt from SysTick timer
 * @return     Nothing
 */
void SysTick_Handler(void) {
    static uint32_t count;

    /* Every 1/2 second */
    if (count++ == TICKRATE_HZ / 2) {
        count = 0;
        Chip_ADC_StartSequencer(LPC_ADC, ADC_SEQA_IDX);
    }
}

/**
 * @brief     main routine for ADC example
 * @return     Function should not exit
 */
int main(void) {
    uint32_t rawSample;
    int j;

    SystemCoreClockUpdate();
    Board_Init();

    /* Setup ADC for 12-bit mode and normal power */
    Chip_ADC_Init(LPC_ADC, 0);
    Chip_ADC_Init(LPC_ADC, ADC_CR_MODE10BIT);

    /* Need to do a calibration after initialization and trim */
    Chip_ADC_StartCalibration(LPC_ADC);
    while (!(Chip_ADC_IsCalibrationDone(LPC_ADC))) {
    }

    /* Setup for maximum ADC clock rate using sycnchronous clocking */
    Chip_ADC_SetClockRate(LPC_ADC, ADC_MAX_SAMPLE_RATE);

    Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX,
            (ADC_SEQ_CTRL_CHANSEL(BOARD_ADC_CH) | ADC_SEQ_CTRL_MODE_EOS));
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
    Chip_SWM_EnableFixedPin(SWM_FIXED_ADC2);
    Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);

    /* Setup threshold 0 low and high values to about 25% and 75% of max */
    Chip_ADC_SetThrLowValue(LPC_ADC, 0, ((1 * 0xFFF) / 4));
    Chip_ADC_SetThrHighValue(LPC_ADC, 0, ((3 * 0xFFF) / 4));

    Chip_ADC_ClearFlags(LPC_ADC, Chip_ADC_GetFlags(LPC_ADC));
    Chip_ADC_EnableInt(LPC_ADC,
            (ADC_INTEN_SEQA_ENABLE | ADC_INTEN_OVRRUN_ENABLE));
    Chip_ADC_SelectTH0Channels(LPC_ADC, ADC_THRSEL_CHAN_SEL_THR1(BOARD_ADC_CH));
    Chip_ADC_SetThresholdInt(LPC_ADC, BOARD_ADC_CH, ADC_INTEN_THCMP_CROSSING);

    /* Enable ADC NVIC interrupt */
    NVIC_EnableIRQ(ADC_SEQA_IRQn);

    Chip_ADC_EnableSequencer(LPC_ADC, ADC_SEQA_IDX);

    SysTick_Config(SystemCoreClock / TICKRATE_HZ);

    /* Endless loop */
    while (1) {
        /* Sleep until something happens */
        __WFI();

        if (thresholdCrossed) {
            thresholdCrossed = false;
            printf("********ADC threshold event********\r\n");
        }

        /* Is a conversion sequence complete? */
        if (sequenceComplete) {
            sequenceComplete = false;

            /* Get raw sample data for channels 0-11 */
            for (j = 0; j < 12; j++) {
                rawSample = Chip_ADC_GetDataReg(LPC_ADC, j);
                /* Show some ADC data */
                if (rawSample & (ADC_DR_OVERRUN | ADC_SEQ_GDAT_DATAVALID)) {
                    printf("Chan: %d Val: %d\r\n", j, ADC_DR_RESULT(rawSample));
                    printf("Threshold range: 0x%x ",
                            ADC_DR_THCMPRANGE(rawSample));
                    printf("Threshold cross: 0x%x\r\n",
                            ADC_DR_THCMPCROSS(rawSample));
                    printf("Overrun: %s ",
                            (rawSample & ADC_DR_OVERRUN) ? "true" : "false");
                    printf("Data Valid: %s\r\n\r\n",
                            (rawSample & ADC_SEQ_GDAT_DATAVALID) ?
                                    "true" : "false");
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

硬故障通常意味着您尝试在允许的地址之外执行代码。如果您没有在向量表中注册该中断,但启用了该中断,则MCU将跳至写入该地址的任何地址,之后程序崩溃。

如何修复取决于工具链。假设LPCXpresso,您有几个设置库的选项(我不特别了解LPCOpen),因此查找向量表的位置因情况而异。但是,无论是否使用ARM,这在大多数MCU上的工作原理都非常相似。在“ crt启动”文件中的某处,应该包含以下内容:

void (* const g_pfnVectors[])(void) = ...

这是一个函数指针数组,它将是在内存中分配给Cortex M上地址0的向量表。您必须将函数放在相关的中断向量上。例如,它可能会说类似

PIN_INT0_IRQHandler,                     // PIO INT0

如果这是您应该实现的中断,则替换该行:

#include "my_irq_stuff.h"
...

void (* const g_pfnVectors[])(void) = 
...
my_INT0,                                 // PIO INT0

假设my_irq_stuff.h包含用于中断服务例程的函数原型my_INT0。实际例程应在相应的.c文件中实现。