#include "FreeRTOS.h" #include "board.h" #include "chip.h" #define ADC_CTR 0x00 #define ADC_CFG 0x04 #define ADC_IMR 0x08 #define ADC_STA 0x0C #define ADC_AUX0 0x14 #define ADC_AUX1 0x18 #define ADC_AUX2 0x1C #define ADC_AUX3 0x20 #define ADC_AUX4 0x38 #define ADC_AUX5 0x3c #define ADC_AUX6 0x40 #define ADC_AUX7 0x44 #define ADC_DBNCNT 0x2C #define ADC_DETINTER 0x30 #define ADC_SCTR 0x34 #define ADC_CLK_FREQ 10000 #define ADC_DEBOUNCE_CNT 0x50 typedef struct adc_private_data { eAdcID id; uint32_t base; uint32_t irq; uint32_t clk_id; adc_int_cb ch_cb[ADC_CH_MAX]; void *ch_cb_priv[ADC_CH_MAX]; } adc_pdata_t; static adc_pdata_t g_adc[ADC_ID_MAX] = { [0] = { .id = 0, .base = REGS_ADC_BASE, .irq = ADC_IRQn, .clk_id = CLK_ADC, }, [1] = { .id = 1, .base = REGS_ADC1_BASE, .irq = ADC1_IRQn, .clk_id = CLK_ADC1, }, [2] = { .id = 2, .base = REGS_ADC2_BASE, .irq = ADC2_IRQn, .clk_id = CLK_ADC2, } }; static uint32_t adc_get_int_bitoff(eAdcChannel ch) { uint32_t bitoff = 0; switch (ch) { case ADC_CH_AUX0: bitoff = 0; break; case ADC_CH_AUX1: bitoff = 3; break; case ADC_CH_AUX2: bitoff = 6; break; case ADC_CH_AUX3: bitoff = 9; break; case ADC_CH_AUX4: bitoff = 16; break; case ADC_CH_AUX5: bitoff = 19; break; case ADC_CH_AUX6: bitoff = 22; break; case ADC_CH_AUX7: bitoff = 25; break; } return bitoff; } static void adc_clear_int_status(adc_pdata_t *adc, eAdcChannel ch, uint32_t int_flg) { uint32_t val, bitoff; bitoff = adc_get_int_bitoff(ch); val = readl(adc->base + ADC_STA); val &= ~((int_flg & ADC_INT_MASK) << bitoff); writel(val, adc->base + ADC_STA); } static uint32_t adc_get_int_status(adc_pdata_t *adc, eAdcChannel ch) { uint32_t bitoff = 0; bitoff = adc_get_int_bitoff(ch); return (readl(adc->base + ADC_STA) >> bitoff) & ADC_INT_MASK; } static uint32_t adc_get_value(adc_pdata_t *adc, eAdcChannel ch) { uint32_t regoff; switch (ch) { case ADC_CH_AUX0: regoff = ADC_AUX0; break; case ADC_CH_AUX1: regoff = ADC_AUX1; break; case ADC_CH_AUX2: regoff = ADC_AUX2; break; case ADC_CH_AUX3: regoff = ADC_AUX3; break; case ADC_CH_AUX4: regoff = ADC_AUX4; break; case ADC_CH_AUX5: regoff = ADC_AUX5; break; case ADC_CH_AUX6: regoff = ADC_AUX6; break; case ADC_CH_AUX7: regoff = ADC_AUX7; break; } return readl(adc->base + regoff); } /* * clk unit = 1/pclk */ static void adc_set_debounce_cnt(adc_pdata_t *adc, uint32_t debounce_cnt) { writel(debounce_cnt & 0xffffff, adc->base + ADC_DBNCNT); } /* * clk unit = 1/adc_clk */ static void adc_set_transform_interval(adc_pdata_t *adc, uint32_t interval) { writel(interval & 0xffff, adc->base + ADC_DETINTER); } static void adc_reset(adc_pdata_t *adc) { uint32_t val; val = readl(adc->base + ADC_CTR); val |= (1 << 0); writel(val, adc->base + ADC_CTR); } static void adc_set_deinter(adc_pdata_t *adc, uint32_t count) { int mincnt, clkid; switch (adc->id) { case ADC0: clkid = CLK_ADC; break; case ADC1: clkid = CLK_ADC1; break; case ADC2: clkid = CLK_ADC2; break; default: return; } mincnt = ADC_DEBOUNCE_CNT * ulClkGetRate(clkid) / 2 / ulClkGetRate(CLK_APB); adc_set_transform_interval(adc, configMAX(mincnt, count)); } static void adc_set_deinter_ms(adc_pdata_t *adc, uint32_t ms) { uint32_t count; count = (ms * ADC_CLK_FREQ)/1000; count /= 5; if(count < 0xffff) adc_set_deinter(adc, count); } static void adc_int_handler(void *para) { adc_pdata_t *adc = (adc_pdata_t *)para; adc_int_cb cb; uint32_t channel; uint32_t status; uint32_t imr; uint32_t int_en; imr = readl(adc->base + ADC_IMR); for (channel = ADC_CH_AUX0; channel < ADC_CH_MAX; channel++) { int_en = ~((imr >> adc_get_int_bitoff((eAdcChannel)channel)) & ADC_INT_MASK); status = adc_get_int_status(adc, (eAdcChannel)channel); if (status) { cb = adc->ch_cb[channel]; if (cb && (status & int_en)) { cb((uint32_t)adc->id, status & int_en, adc_get_value(adc, (eAdcChannel)channel), adc->ch_cb_priv[channel]); } adc_clear_int_status(adc, (eAdcChannel)channel, status); } } } int adc_int_threshold_sel(eAdcID adc_id, int high) { uint32_t bitoff; bitoff = adc_id - ADC0 + 11; if (high) vSysctlConfigure(SYS_ANA_CFG, bitoff, 1, 1); else vSysctlConfigure(SYS_ANA_CFG, bitoff, 1, 0); return 0; } int adc_interrupt_enable(eAdcID id, eAdcChannel ch, uint32_t int_flg, int enable) { adc_pdata_t *adc; uint32_t bitoff; uint32_t val; if (id >= ADC_ID_MAX) { printf("%s, Invalid id:%d\n", __func__, id); return -1; } adc = &g_adc[id]; bitoff = adc_get_int_bitoff(ch); val = readl(adc->base + ADC_IMR); if (enable) val &= ~((int_flg & ADC_INT_MASK) << bitoff); else val |= ((int_flg & ADC_INT_MASK) << bitoff); writel(val, adc->base + ADC_IMR); return 0; } int adc_force_conv_enable(eAdcID id, eAdcChannel ch, int enable) { adc_pdata_t *adc; uint32_t bitoff; uint32_t val; if (id >= ADC_ID_MAX) { printf("%s, Invalid id:%d\n", __func__, id); return -1; } adc = &g_adc[id]; val = readl(adc->base + ADC_CTR); if (ch < ADC_CH_AUX4) bitoff = ch - ADC_CH_AUX0 + 13; else bitoff = ch - ADC_CH_AUX4 + 28; if (enable) val |= (1 << bitoff); else val &= ~(1 << bitoff); writel(val, adc->base + ADC_CTR); return 0; } /* * enable = 1,ADC值大于阈值时,触发中断。 * enable = 0,ADC值小于阈值时,触发中断。 */ int adc_det_high_valid_enable(eAdcID id, eAdcChannel ch, int enable) { adc_pdata_t *adc; uint32_t bitoff; uint32_t val; if (id >= ADC_ID_MAX) { printf("%s, Invalid id:%d\n", __func__, id); return -1; } adc = &g_adc[id]; val = readl(adc->base + ADC_CTR); if (ch < ADC_CH_AUX4) bitoff = ch - ADC_CH_AUX0 + 8; else bitoff = ch - ADC_CH_AUX4 + 24; if (enable) val |= (1 << bitoff); else val &= ~(1 << bitoff); writel(val, adc->base + ADC_CTR); return 0; } uint32_t adc_get_chn_val_force(eAdcID id, eAdcChannel ch) { int i; uint32_t adc_v; configASSERT(ch >= ADC_CH_AUX0 && ch <= ADC_CH_AUX7); for (i = ADC_CH_AUX0; i <= ADC_CH_AUX7; i++) { if (ch == i) { adc_enable(id, (eAdcChannel)i, 1); adc_force_conv_enable(id, (eAdcChannel)i, 1); adc_clear_int_status(&g_adc[id], (eAdcChannel)i, ADC_INT_MASK); } else { adc_enable(id, (eAdcChannel)i, 0); adc_force_conv_enable(id, (eAdcChannel)i, 0); } } while(!(adc_get_int_status(&g_adc[id], ch) & ADC_VALUE_INT)) { vTaskDelay(1); } return adc_get_value(&g_adc[id], ch); } int adc_register_int_cb(eAdcID id, eAdcChannel ch, adc_int_cb cb, void *user_param) { adc_pdata_t *adc; if (id >= ADC_ID_MAX) { printf("%s, Invalid id:%d\n", __func__, id); return -1; } adc = &g_adc[id]; adc->ch_cb[ch] = cb; adc->ch_cb_priv[ch] = user_param; return 0; } int adc_enable(eAdcID id, eAdcChannel ch, int enable) { adc_pdata_t *adc; uint32_t bitoff; uint32_t val; if (id >= ADC_ID_MAX) { printf("%s, Invalid id:%d\n", __func__, id); return -1; } adc = &g_adc[id]; if (id < ADC2) { // ADC 管脚需要将其设置为gpio输入 gpio_direction_input((id - ADC0) * ADC_CH_MAX + ch + 111); } else { // 注:ADC2的AUX0~7的gpio功能由mcu控制,请在mcu上将对应gpio设置为输入。 vSysctlConfigure(SYS_PAD_PUDCTL14, ch - ADC_CH_AUX0 + 16, 1, 1); } val = readl(adc->base + ADC_CTR); if (ch < ADC_CH_AUX4) bitoff = ch - ADC_CH_AUX0 + 3; else bitoff = ch - ADC_CH_AUX4 + 20; if (enable) { val |= (1 << bitoff); } else { val &= ~(1 << bitoff); } writel(val, adc->base + ADC_CTR); return 0; } int adc_init(void) { adc_pdata_t *adc; eAdcChannel channel; int id; for (id = 0; id < ADC_ID_MAX; id++) { #ifndef ADC0_SUPPORT if (id == ADC0) continue; #endif #ifndef ADC1_SUPPORT if (id == ADC1) continue; #endif #ifndef ADC2_SUPPORT if (id == ADC2) continue; #endif adc = &g_adc[id]; vClkSetRate(adc->clk_id, ADC_CLK_FREQ); adc_reset(adc); for (channel = 0; channel < ADC_CH_MAX; channel++) { adc->ch_cb[channel] = NULL; adc->ch_cb_priv[channel] = NULL; /* disable all adc channel */ adc_enable(id, channel, 0); /* disable and clear irq */ adc_interrupt_enable(id, channel, ADC_INT_MASK, 0); adc_clear_int_status(adc, channel, ADC_INT_MASK); } /* set debounce count */ adc_set_debounce_cnt(adc, ADC_DEBOUNCE_CNT); adc_set_deinter_ms(adc, 100); request_irq(adc->irq, 0, adc_int_handler, (void *)adc); } return 0; }