CC3200在sl_Start函数处不断重启复位的原因解析

CC3200重启问题解决
本文记录了CC3200设备在启动网络功能时频繁重启的问题排查过程。通过对供电不足、软件版本不匹配等原因的逐一排除,最终通过硬件修改解决了问题。

1. 使用过程中,自己写的工程,发现CC3200一直重启,首先需要定位出现重启的函数?看门狗复位,还是程序跑飞复位?NWP的版本不匹配?经过测试找到出问题的函数,这个函数是启动网络的函数。

lRetVal = sl_Start(NULL, NULL, NULL);  

2. 既然是上面的函数,原因有几种可能,供电不足,NWP版本不匹配,NWP没烧写。首先看下供电,另外加了一块板子进行供电。程序偶尔可以正常运行,稍微前进了一步。分析是目前使用的板子,供电电流可能比较小,导致异常。不过在此处,我们使用ADC的例程是正常运行的,本次由于我们启动了网络,导致瞬间电流很大,供电不足,所以重启。

3. 看下原理图的供电,找下上面的电源芯片,电流800mA,难道带不起来?还是自己电脑的USB电流太小?换个SPX1117M3-L-3-3测试一下也是不行,是不是有限流的电阻?

4. 去掉了保险丝还是不行,或者可以烧写个其他的带wifi启动的例程测试一下,看是否不断重启。测试了一下get_weather这个例程,不会重启。复位原因码如下

#define PRCM_MCU_RESET            0x00000004

5. 除了供电还有什么原因导致一直重启?函数不是成对调用的?烧写不同NWP版本也不行,格式化再测试一下。还是不行,增加了一行代码

    sl_Stop(SL_STOP_TIMEOUT);
    lRetVal = sl_Start(0, 0, 0);  // 第一次启动

直接报错

Assert: D:\ti\CC3200SDK_1.1.0\LSD4WF-3221I5SS_SRC_V1.00.05\third_party\FreeRTOS\source\queue.c 1177

10. 系统堆栈不够,还是任务堆栈不够?堆从0x800增加到0x1000,

define block HEAP with alignment = 8, size = 0x0001000 { };

11. 增大任务的堆栈测试一下,还是不断的重启。

12. 换个uniflash的版本测试一下,芯片硬件版本[11:23:12] INFO: DEVICE CC3200 ES1.33,是量产版本。

13.硬件修改一下,供电测试一下,在模块供电端+3.3V和GND之间增加了一个22uF的贴片电容,和100uF的电解电容,问题解决。不会在重启了,后来去掉100uF的电解电容也还是正常,所以只用增加一个22uF的贴片电容即可。问题解决。

转载于:https://www.cnblogs.com/429512065qhq/p/8549787.html

/* * Copyright (c) 2018 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @brief PWM controller driver for Actions SoC */ #include <errno.h> #include <sys/__assert.h> #include <stdbool.h> #include <kernel.h> #include <device.h> #include <init.h> #include <drivers/pwm.h> #include <soc.h> #include <drivers/dma.h> #include <errno.h> #include <soc_regs.h> #include "pwm_context.h" #include <drivers/cfg_drv/dev_config.h> #include <soc.h> #define LOG_LEVEL CONFIG_LOG_PWM_DEV_LEVEL #include <logging/log.h> LOG_MODULE_REGISTER(pwm); #define DMA_IRQ_TC (0) /* DMA completion flag */ #define DMA_IRQ_HF (1) /* DMA half-full flag */ enum PWM_GROUP { PWM_GROUP0_REG, PWM_GROUP1_REG, PWM_GROUP2_REG, PWM_GROUP3_REG, PWM_GROUP4_REG, PWM_GROUP5_REG, PWM_GROUP_MAX, }; #define PWM_FIFO_REG (6) #define PWM_IR_REG (7) #define PWM_INTCTL_REG (8) #define PWM_PENDING_REG (9) enum PWM_MODE { PWM_DEFAULT_REG, PWM_FIX_INIT, PWM_BTH_INIT, PWM_PRG_INIT, PWM_IR_INIT, PWM_MODE_MAX, }; #define PWM_MODE_MASK (0x7) #define PWM_chan(x) (1 << (3 + x)) #define PWM_chan_act(x) (1 << (9 + x)) #define PWM_chan_act_MASK (0x7e00) #define ir_code_pre_sym(a) ((a&0x8000) >> 15) #define ir_code_pre_val(a) ((a&0x7f00) >> 8) #define ir_code_pos_sym(a) ((a&0x80) >> 7) #define ir_code_pos_val(a) ((a&0x7f) >> 0) #define PWM_IR_REPEAT_MODE (0 << 8) #define PWM_IR_CYCLE_MODE (1 << 8) #define PWM_IR_MASK (0xff) #define PWM_IR_TX_MARGIN (1000) #define PWM_IR_TIMEOUT (1) /* IR_RX_ANA_CTL */ #define TX_ANA_EN (1) #define RX_ANA_CTL(base) (base + 0xf0) #define TX_ANA_CTL(base) (base + 0xf4) #define IR_TX_DINV (1 << 8) #define IR_TX_SR(X) (X << 4) #define IR_TX_POUT(X) (X << 1) #define IR_TX_EN (1) struct pwm_acts_data { struct k_sem dma_sync; struct k_sem ir_sync; struct k_sem ir_transfer_sync; struct device *dma_dev; int dma_chan; int (*program_callback)(void *cb_data, u8_t reason); void *cb_data; u8_t program_pin; u16_t group_init_status[6]; u32_t pwm_ir_sw; u32_t buf_num; u32_t pwm_ir_mode; struct k_timer timer; u32_t ir_event_timeout; u32_t pwm_ir_lc[2]; u32_t pwm_ir_ll[2]; u32_t pwm_ir_ld[2]; u32_t pwm_ir_pl[2]; u32_t pwm_ir_pd0[2]; u32_t pwm_ir_pd1[2]; u32_t pwm_ir_sl[2]; u8_t ir_pout; bool manual_stop_flag; }; struct pwm_acts_config { u32_t base; u32_t pwmclk_reg; u32_t cycle; u8_t clock_id; u8_t reset_id; const struct acts_pin_config *pinmux; u8_t pinmux_size; void (*irq_config_func)(void); const char *dma_dev_name; u8_t txdma_id; u8_t flag_use_dma; }; void pwm_acts_repeat_event_process(const struct pwm_acts_config *cfg, u32_t pending) { uint32_t pwm_base; if(pending & PWM_PENDING_G0REPEAT) { sys_write32(~(PWM_PENDING_G0REPEAT) & sys_read32(PWM_INT_CTL(cfg->base)), PWM_INT_CTL(cfg->base)); pwm_base = PWM0_BASE(cfg->base); struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)pwm_base; pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(0,0xfff)); } if(pending & PWM_PENDING_G1REPEAT) { sys_write32(~(PWM_PENDING_G1REPEAT) & sys_read32(PWM_INT_CTL(cfg->base)), PWM_INT_CTL(cfg->base)); pwm_base = PWM1_BASE(cfg->base); struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)pwm_base; pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(0,0xfff)); } if(pending & PWM_PENDING_G2REPEAT) { sys_write32(~(PWM_PENDING_G2REPEAT) & sys_read32(PWM_INT_CTL(cfg->base)), PWM_INT_CTL(cfg->base)); pwm_base = PWM2_BASE(cfg->base); struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)pwm_base; pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(0,0x3)); } if(pending & PWM_PENDING_G3REPEAT) { sys_write32(~(PWM_PENDING_G3REPEAT) & sys_read32(PWM_INT_CTL(cfg->base)), PWM_INT_CTL(cfg->base)); pwm_base = PWM3_BASE(cfg->base); struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)pwm_base; pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(0,0x3)); } if(pending & PWM_PENDING_G4REPEAT) { sys_write32(~(PWM_PENDING_G4REPEAT) & sys_read32(PWM_INT_CTL(cfg->base)), PWM_INT_CTL(cfg->base)); pwm_base = PWM4_BASE(cfg->base); struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)pwm_base; pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(0,0x3)); } } static void pwm_acts_ir_timeout_event(struct k_timer *timer) { struct pwm_acts_data *data = k_timer_user_data_get(timer); struct acts_pwm_ir *pwm_ir = (struct acts_pwm_ir *)PWM_IR(PWM_REG_BASE); pwm_ir->ir_ll = data->pwm_ir_ll[data->pwm_ir_sw]; pwm_ir->ir_ld = data->pwm_ir_ld[data->pwm_ir_sw]; pwm_ir->ir_pd0 = data->pwm_ir_pd0[data->pwm_ir_sw]; pwm_ir->ir_pd1 = data->pwm_ir_pd1[data->pwm_ir_sw]; pwm_ir->ir_sl = data->pwm_ir_sl[data->pwm_ir_sw]; pwm_ir->ir_pl = data->pwm_ir_pl[data->pwm_ir_sw]; pwm_ir->ir_lc = data->pwm_ir_lc[data->pwm_ir_sw]; pwm_ir->ir_ctl |= PWM_IRCTL_CU; if(data->pwm_ir_sw < data->buf_num) data->pwm_ir_sw++; if(data->pwm_ir_sw >= data->buf_num) { if(data->pwm_ir_mode & PWM_IR_CYCLE_MODE) data->pwm_ir_sw = 0; else data->pwm_ir_sw = data->buf_num -1; } k_timer_stop(&data->timer); } void pwm_acts_isr(void *arg) { struct device *dev = (struct device *)arg; struct pwm_acts_data *data = dev->data; const struct pwm_acts_config *cfg = dev->config; struct acts_pwm_ir *pwm_ir = (struct acts_pwm_ir *)PWM_IR(cfg->base); unsigned int key; key = irq_lock(); if((sys_read32(PWM_PENDING(cfg->base)) & PWM_PENDING_IRSS) && (data->buf_num > 1)) { pwm_ir->ir_ctl |= PWM_IRCTL_CU; u16_t timeout; timeout = (data->ir_event_timeout * pwm_ir->ir_ll)/1000 + PWM_IR_TIMEOUT; k_timer_start(&data->timer, K_MSEC(timeout), K_MSEC(timeout)); } irq_unlock(key); if(sys_read32(PWM_PENDING(cfg->base)) & PWM_PENDING_IRAE) { if (data->manual_stop_flag) { k_sem_give(&data->ir_sync); data->group_init_status[PWM_GROUP5_REG] = 0; } else { /* continue to send repeat code or data code */ pwm_ir->ir_ctl |= PWM_IRCTL_START; } } if(sys_read32(PWM_PENDING(cfg->base)) & (PWM_PENDING_REPEAT_MASK & sys_read32(PWM_INT_CTL(cfg->base)))) { pwm_acts_repeat_event_process(cfg, sys_read32(PWM_PENDING(cfg->base))); } sys_write32(0xffffffff, PWM_PENDING(cfg->base)); } static void pwm_acts_set_clk(const struct pwm_acts_config *cfg, uint32_t group, uint32_t freq_hz) { clk_set_rate(cfg->clock_id + group, freq_hz); k_busy_wait(100); } static u32_t pwm_acts_get_group(u32_t pwm) { u32_t group; if(pwm > 15) return -EINVAL; if((pwm) < 6) group = PWM_GROUP0_REG; else if((pwm) < 12) group = PWM_GROUP1_REG; else group = pwm -10; return group; } static u32_t pwm_acts_get_reg_base(u32_t base, uint32_t REG) { u32_t controller_reg; switch(REG) { case PWM_GROUP0_REG: controller_reg = PWM0_BASE(base); break; case PWM_GROUP1_REG: controller_reg = PWM1_BASE(base); break; case PWM_GROUP2_REG: controller_reg = PWM2_BASE(base); break; case PWM_GROUP3_REG: controller_reg = PWM3_BASE(base); break; case PWM_GROUP4_REG: controller_reg = PWM4_BASE(base); break; case PWM_GROUP5_REG: controller_reg = PWM5_BASE(base); break; case PWM_FIFO_REG: controller_reg = PWM_FIFO(base); break; case PWM_IR_REG: controller_reg = PWM_IR(base); break; case PWM_INTCTL_REG: controller_reg = PWM_INT_CTL(base); break; case PWM_PENDING_REG: controller_reg = PWM_PENDING(base); break; default: return -EINVAL; } return controller_reg; } /* * Set the period and pulse width for a PWM pin. * * Parameters * dev: Pointer to PWM device structure * pwm: PWM channel to set * period_cycles: Period (in timer count) * pulse_cycles: Pulse width (in timer count). * @param flags Flags for pin configuration (polarity). * return 0, or negative errno code */ static void pwm_acts_groupx_fix_init(u32_t base, u32_t period_cycles, u32_t pulse_cycles, u8_t chan, u8_t function, pwm_flags_t flags) { struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)base; u32_t pol_param; pwm->ctrl |= PWMx_CTRL_CHx_MODE_SEL(chan,1); if(chan < 4) { pol_param = PWMx_CH_CTL0_CHx_POL_SEL(chan); if(flags) pwm->ch_ctrl0 |= pol_param; else pwm->ch_ctrl0 = pwm->ch_ctrl0 & (~pol_param); } else { pol_param = PWMx_CH_CTL1_CHx_POL_SEL(chan); if(flags) pwm->ch_ctrl1 |= pol_param; else pwm->ch_ctrl1 = pwm->ch_ctrl1 & (~pol_param); } if(function) { pwm->cntmax = period_cycles; pwm->cmp[chan] = pulse_cycles; if((pwm->ctrl & PWMx_CTRL_HUA) == 0) pwm->ctrl |= PWMx_CTRL_HUA; else { k_usleep(30); pwm->ctrl |= PWMx_CTRL_HUA; } return; } pwm->cntmax = period_cycles; pwm->cmp[chan] = pulse_cycles; pwm->ctrl |= PWMx_CTRL_CNT_EN;//norlmal mode } static int pwm_acts_pin_set(const struct device *dev, uint32_t pwm, u32_t period_cycles, u32_t pulse_cycles, pwm_flags_t flags) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; uint32_t base,group; u16_t status; LOG_INF("PWM@%d set period cycles %d ms, pulse cycles %d ms", pwm, period_cycles, pulse_cycles); // period_cycles = period_cycles * pwm_normal_clk_rate / 1000; // pulse_cycles = pulse_cycles * pwm_normal_clk_rate / 1000; if (pulse_cycles > period_cycles) { LOG_ERR("pulse cycles %d is biger than period's %d", pulse_cycles, period_cycles); return -EINVAL; } group = pwm_acts_get_group(pwm); status = data->group_init_status[group]; if((status&PWM_MODE_MASK) != PWM_DEFAULT_REG && (status&PWM_MODE_MASK) != PWM_FIX_INIT) { LOG_ERR("start a fix mode but have not stop this group bfore!"); return -EINVAL; } pwm = (pwm > 5)?pwm-6:pwm; pwm = (pwm > 5)?pwm-4-group:pwm; base = pwm_acts_get_reg_base(cfg->base, group); if((status & PWM_chan(pwm)) == 0)//this group_chan have not initialized yet. pwm_acts_groupx_fix_init(base,period_cycles,pulse_cycles,pwm, 0, flags); else pwm_acts_groupx_fix_init(base,period_cycles,pulse_cycles,pwm, 1, flags); if(pulse_cycles == 0) { data->group_init_status[group] = data->group_init_status[group] & ~(PWM_chan_act(pwm)); } else { data->group_init_status[group] = PWM_FIX_INIT | PWM_chan(pwm) | status; data->group_init_status[group] |= PWM_chan_act(pwm); } return 0; } /* * Set the period and pulse width for a PWM pin. * * Parameters * dev: Pointer to PWM device structure * pwm: PWM channel to set * ctrl: breath mode control * return 0, or negative errno code */ #ifdef CONFIG_PWM_TAI_FULL_FUNC static void pwm_acts_groupx_breath_init(u32_t base, u8_t chan, pwm_breath_ctrl_t *ctrl) { struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)base; struct acts_pwm_breath_mode *breath = (struct acts_pwm_breath_mode *)(PWM_BREATH(base) + chan * PWM_BREATH_REG_SIZE); pwm->cntmax = ctrl->pwm_count_max; if(ctrl->stage_a_step) breath->pwm_bth_a = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_a_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_a_repeat) | PWMx_BTHxy_STEP(ctrl->stage_a_step); else breath->pwm_bth_a &= (~PWMx_BTHxy_EN); if(ctrl->stage_b_step) breath->pwm_bth_b = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_b_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_b_repeat) | PWMx_BTHxy_STEP(ctrl->stage_b_step); else breath->pwm_bth_b &= (~PWMx_BTHxy_EN); if(ctrl->stage_c_step) breath->pwm_bth_c = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_c_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_c_repeat) | PWMx_BTHxy_STEP(ctrl->stage_c_step); else breath->pwm_bth_c &= (~PWMx_BTHxy_EN); if(ctrl->stage_d_step) breath->pwm_bth_d = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_d_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_d_repeat) | PWMx_BTHxy_STEP(ctrl->stage_d_step); else breath->pwm_bth_d &= (~PWMx_BTHxy_EN); if(ctrl->stage_e_step) breath->pwm_bth_e = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_e_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_e_repeat) | PWMx_BTHxy_STEP(ctrl->stage_e_step); else breath->pwm_bth_e &= (~PWMx_BTHxy_EN); if(ctrl->stage_f_step) breath->pwm_bth_f = PWMx_BTHxy_EN | PWMx_BTHxy_XS(ctrl->stage_f_pwm) | PWMx_BTHxy_REPEAT(ctrl->stage_f_repeat) | PWMx_BTHxy_STEP(ctrl->stage_f_step); else breath->pwm_bth_f &= (~PWMx_BTHxy_EN); if(ctrl->stage_low_wait) breath->pwm_bth_hl = PWMx_BTHx_HL_L(ctrl->stage_low_wait) | PWMx_BTHx_HL_LEN; else breath->pwm_bth_hl &= (~PWMx_BTHx_HL_LEN); if(ctrl->stage_high_wait) breath->pwm_bth_hl = PWMx_BTHx_HL_H(ctrl->stage_high_wait) | PWMx_BTHx_HL_HEN; else breath->pwm_bth_hl &= (~PWMx_BTHx_HL_HEN); if(ctrl->start_dir) breath->pwm_bth_st = PWMx_BTHx_ST_ST(ctrl->start_pwm) | PWMx_BTHx_ST_DIR; else breath->pwm_bth_st = PWMx_BTHx_ST_ST(ctrl->start_pwm); pwm->ctrl |= PWMx_CTRL_CHx_MODE_SEL(chan,3) | PWMx_CTRL_CNT_EN;//breath mode } static int pwm_acts_set_breath_mode(const struct device *dev, uint32_t pwm, pwm_breath_ctrl_t *ctrl) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; uint32_t base,group; u16_t status; group = pwm_acts_get_group(pwm); status = data->group_init_status[group]; if((status&0x3) != PWM_BTH_INIT && (status&0x3)) {//not brearh mode or default LOG_ERR("start a breath mode but have not stop this group bfore!"); return -EINVAL; } pwm = (pwm > 5)?pwm-6:pwm; pwm = (pwm > 5)?pwm-4-group:pwm; base = pwm_acts_get_reg_base(cfg->base, group); if(group == PWM_GROUP1_REG || group == PWM_GROUP2_REG) pwm_acts_groupx_breath_init(base, pwm, ctrl); else { LOG_ERR("unsuported channel: %d",pwm); return -EINVAL; } data->group_init_status[group] = PWM_BTH_INIT | PWM_chan(pwm) | status; return 0; } #endif /* * Set the period and pulse width for a PWM pin. * * Parameters * dev: Pointer to PWM device structure * pwm: PWM channel to set * ctrl: program mode control * return 0, or negative errno code */ #ifdef CONFIG_PWM_TAI_FULL_FUNC static void dma_done_callback(const struct device *dev, void *callback_data, uint32_t ch , int type) { struct pwm_acts_data *data = (struct pwm_acts_data *)callback_data; //if (type != DMA_IRQ_TC) //return; LOG_DBG("pwm dma transfer is done"); k_sem_give(&data->dma_sync); } static int pwm_acts_start_dma(const struct pwm_acts_config *cfg, struct pwm_acts_data *data, uint32_t dma_chan, uint16_t *buf, int32_t len, bool is_tx, void *callback) { struct acts_pwm_fifo *pwm_fifo = (struct acts_pwm_fifo *)PWM_FIFO(cfg->base); struct dma_config dma_cfg = {0}; struct dma_block_config dma_block_cfg = {0}; if (callback) { dma_cfg.dma_callback = (dma_callback_t)callback; dma_cfg.user_data = data; dma_cfg.complete_callback_en = 1; } dma_cfg.block_count = 1; dma_cfg.head_block = &dma_block_cfg; dma_block_cfg.block_size = len; if (is_tx) { dma_cfg.dma_slot = cfg->txdma_id; dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL; dma_block_cfg.source_address = (uint32_t)buf; dma_block_cfg.dest_address = (uint32_t)&pwm_fifo->fifodat; dma_cfg.dest_data_size = 2; } else { return -EINVAL; } dma_cfg.source_burst_length = 4; if (dma_config(data->dma_dev, dma_chan, &dma_cfg)) { LOG_ERR("dma%d config error", dma_chan); return -1; } if (dma_start(data->dma_dev, dma_chan)) { LOG_ERR("dma%d start error", dma_chan); return -1; } return 0; } static void pwm_acts_stop_dma(const struct pwm_acts_config *cfg, struct pwm_acts_data *data, uint32_t dma_chan) { dma_stop(data->dma_dev, dma_chan); } static int pwm_acts_wait_fifo_staus(struct acts_pwm_fifo *pwm_fifo, uint16_t timeout) { int start_time; start_time = k_uptime_get_32(); while(!(pwm_fifo->fifosta&PWM_FIFOSTA_EMPTY)) { if(k_uptime_get_32() - start_time > 500) return 0; } return -EINVAL; } static int pwm_acts_dma_transfer(const struct pwm_acts_config *cfg, struct pwm_acts_data *data, u8_t chan, pwm_program_ctrl_t *ctrl) { struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)cfg->base; struct acts_pwm_fifo *pwm_fifo = (struct acts_pwm_fifo *)PWM_FIFO(cfg->base); int ret; pwm->ctrl |= PWMx_CTRL_CHx_MODE_SEL(chan,2) | PWMx_CTRL_CM | PWMx_CTRL_RM; if(ctrl->cntmax) { pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CM); pwm->cntmax = ctrl->cntmax; } if(ctrl->repeat) { pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_RM); pwm->repeat = ctrl->repeat; } if(pwm_acts_wait_fifo_staus(pwm_fifo, 500)) { LOG_ERR("time out error, pwm fifo can not be empty!"); return -EINVAL; } pwm_fifo->fifoctl = PWM_FIFOCTL_START; ret = pwm_acts_start_dma(cfg, data, data->dma_chan, ctrl->ram_buf, ctrl->ram_buf_len, 1, dma_done_callback); if (ret) { LOG_ERR("faield to start dma chan 0x%x\n", data->dma_chan); goto out; } pwm->ctrl |= PWMx_CTRL_CNT_EN; /* wait until dma transfer is done */ k_sem_take(&data->dma_sync, K_FOREVER);//K_MSEC(500));// out: pwm_acts_stop_dma(cfg, data, data->dma_chan); if(pwm_acts_wait_fifo_staus(pwm_fifo, 500)) { LOG_ERR("time out error, pwm fifo can not be empty!"); return -EINVAL; } pwm->ctrl = pwm->ctrl & ~(PWMx_CTRL_CHx_MODE_SEL(chan,2) | PWMx_CTRL_CM | PWMx_CTRL_RM | PWMx_CTRL_CNT_EN); pwm_fifo->fifoctl = pwm_fifo->fifoctl & ~(PWM_FIFOCTL_START); return ret; } static int pwm_acts_set_program_mode(const struct device *dev, uint32_t pwm, pwm_program_ctrl_t *ctrl) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; uint32_t base,group; u16_t status; group = pwm_acts_get_group(pwm); status = data->group_init_status[group]; if((status&0x3) != PWM_PRG_INIT && (status&0x3)) {//not program mode or default LOG_ERR("start a breath mode but have not stop this group bfore!"); return -EINVAL; } pwm = (pwm > 5)?pwm-6:pwm; pwm = (pwm > 5)?pwm-4-group:pwm; base = pwm_acts_get_reg_base(cfg->base, group); if(group == PWM_GROUP0_REG || group == PWM_GROUP1_REG || group == PWM_GROUP2_REG) { pwm_acts_dma_transfer(cfg, data, pwm, ctrl);//这里有问题的需要修改,ctrl无法覆盖到group2和group1 } else { LOG_ERR("unsuported channel: %d",pwm); return -EINVAL; } // data->group_init_status[group] = PWM_BTH_INIT | PWM_chan(pwm) | status; return 0; } #endif //#define TX_ANA_CTL(base) (base + 0xf4) //#define IR_TX_DINV (1 << 8) //#define IR_TX_SR(X) (X << 4) //#define IR_TX_POUT(X) (X << 1) //#define IR_TX_EN (1) #if 0 static void pwm_acts_ir_reg_dump(struct acts_pwm_ir *pwm_ir) { printk("pwm_ir->ir_asc :%d\n", pwm_ir->ir_asc ); printk("pwm_ir->ir_duty :%d\n", pwm_ir->ir_duty ); printk("pwm_ir->ir_lc :%d\n", pwm_ir->ir_lc ); printk("pwm_ir->ir_ld :%d\n", pwm_ir->ir_ld ); printk("pwm_ir->ir_ll :%d\n", pwm_ir->ir_ll ); printk("pwm_ir->ir_pd0 :%d\n", pwm_ir->ir_pd0 ); printk("pwm_ir->ir_pd1 :%d\n", pwm_ir->ir_pd1 ); printk("pwm_ir->ir_period :%d\n", pwm_ir->ir_period ); printk("pwm_ir->ir_pl :%d\n", pwm_ir->ir_pl ); printk("pwm_ir->ir_pl0_post :%d\n", pwm_ir->ir_pl0_post ); printk("pwm_ir->ir_pl0_pre :%d\n", pwm_ir->ir_pl0_pre ); printk("pwm_ir->ir_pl1_post :%d\n", pwm_ir->ir_pl1_post ); printk("pwm_ir->ir_pl1_pre :%d\n", pwm_ir->ir_pl1_pre ); printk("pwm_ir->ir_sl :%d\n", pwm_ir->ir_sl ); } #endif static void pwm_acts_ir_tx(const struct pwm_acts_config *cfg, struct pwm_acts_data *data, u8_t chan, struct pwm_ir_mode_param_t *ctrl, uint32_t base) { struct acts_pwm_groupx *pwm = (struct acts_pwm_groupx *)base; struct acts_pwm_ir *pwm_ir = (struct acts_pwm_ir *)PWM_IR(cfg->base); u16_t mode; acts_pinmux_set(cfg->pinmux[cfg->pinmux_size - 1].pin_num, cfg->pinmux[cfg->pinmux_size - 1].mode); #if TX_ANA_EN sys_write32(0, RX_ANA_CTL(GPIO_REG_BASE)); sys_write32(IR_TX_EN | IR_TX_POUT(data->ir_pout), TX_ANA_CTL(GPIO_REG_BASE)); #endif while(pwm_ir->ir_ctl&PWM_IRCTL_START); data->pwm_ir_mode = ctrl[0].mode; mode = ctrl[0].mode & PWM_IR_MASK; pwm->ctrl |= PWMx_CTRL_CHx_MODE_SEL(chan,2); pwm_ir->ir_asc = ctrl[0].ir_asc; pwm_ir->ir_duty = ctrl[0].ir_duty; pwm_ir->ir_lc = ctrl[0].ir_lc; pwm_ir->ir_ld = ctrl[0].ir_ld; pwm_ir->ir_ll = ctrl[0].ir_ll; pwm_ir->ir_pd0 = ctrl[0].ir_pd0; pwm_ir->ir_pd1 = ctrl[0].ir_pd1; pwm_ir->ir_period = ctrl[0].ir_period; pwm_ir->ir_pl = ctrl[0].ir_pl; pwm_ir->ir_pl0_post = ctrl[0].ir_pl0_post; pwm_ir->ir_pl0_pre = ctrl[0].ir_pl0_pre; pwm_ir->ir_pl1_post = ctrl[0].ir_pl1_post; pwm_ir->ir_pl1_pre = ctrl[0].ir_pl1_pre; pwm_ir->ir_sl = ctrl[0].ir_sl; // pwm_acts_ir_reg_dump(pwm_ir); if(ctrl[0].buf_num > 1) { data->pwm_ir_sw = 1; data->pwm_ir_lc[0] = ctrl[0].ir_lc; data->pwm_ir_ld[0] = ctrl[0].ir_ld; data->pwm_ir_ll[0] = ctrl[0].ir_ll; data->pwm_ir_pd0[0] = ctrl[0].ir_pd0; data->pwm_ir_pd1[0] = ctrl[0].ir_pd1; data->pwm_ir_pl[0] = ctrl[0].ir_pl; data->pwm_ir_sl[0] = ctrl[0].ir_sl; data->pwm_ir_lc[1] = ctrl[1].ir_lc; data->pwm_ir_ld[1] = ctrl[1].ir_ld; data->pwm_ir_ll[1] = ctrl[1].ir_ll; data->pwm_ir_pd0[1] = ctrl[1].ir_pd0; data->pwm_ir_pd1[1] = ctrl[1].ir_pd1; data->pwm_ir_pl[1] = ctrl[1].ir_pl; data->pwm_ir_sl[1] = ctrl[1].ir_sl; } data->manual_stop_flag = false; data->buf_num = ctrl[0].buf_num; sys_write32(0xffffffff, PWM_PENDING(cfg->base)); sys_write32(PWM_INTCTL_IRAE | PWM_INTCTL_IRSS, PWM_INT_CTL(cfg->base)); pwm_ir->ir_ctl = PWM_IRCTL_PLED | PWM_IRCTL_START; pwm->ctrl |= PWMx_CTRL_CNT_EN; } static u32_t pwm_acts_data_cal(u32_t data, u32_t buf_num) { u32_t cal_val = 0; u32_t cal_dat = data; while(buf_num > 0) { if(cal_dat & 0x1) cal_val++; buf_num--; cal_dat = cal_dat >> 1; } return cal_val; } static u32_t pwm_acts_ir_get_len(u32_t ld) { u32_t len = 0; for(int i = 0; i < 32; i++) { if(ld & 0x80000000) break; len++; ld = ld << 1; } len = 32 - len; return len; } static void pwm_acts_ir_param_sw(struct ir_tx_data_param *ctrl, struct pwm_ir_mode_param_t *param, u32_t loc, struct ir_tx_protocol_param *protocol_param) { u32_t val, sym, ld_len, protocol; u16_t cr_rate; protocol = ctrl->mode; if(ctrl->rate) cr_rate = ctrl->rate/100; else cr_rate = protocol_param->ir_cr_rate; param->ir_period = pwm_clk_rate/(cr_rate * 1000); if(ctrl->duty) param->ir_duty = param->ir_period *10/ctrl->duty; else param->ir_duty = param->ir_period/3; param->ir_lc = cr_rate * protocol_param->ir_lc_bit_length/1000; sym = ir_code_pre_sym(protocol_param->ir_0_code) << 16; val = ir_code_pre_val(protocol_param->ir_0_code) * protocol_param->code_bit_length; val = val * cr_rate/1000; if(sym) val = val + 1;//process remainder param->ir_pl0_pre = sym | val; sym = ir_code_pos_sym(protocol_param->ir_0_code) << 16; val = ir_code_pos_val(protocol_param->ir_0_code) * protocol_param->code_bit_length; val = val * cr_rate/1000; if(sym) val = val + 1;//process remainder param->ir_pl0_post = sym | val; sym = ir_code_pre_sym(protocol_param->ir_1_code) << 16; val = ir_code_pre_val(protocol_param->ir_1_code) * protocol_param->code_bit_length; val = val * cr_rate/1000; if(sym) val = val + 1;//process remainder param->ir_pl1_pre = sym | val; sym = ir_code_pos_sym(protocol_param->ir_1_code) << 16; val = ir_code_pos_val(protocol_param->ir_1_code) * protocol_param->code_bit_length; val = val * cr_rate/1000; if(sym) val = val + 1;//process remainder param->ir_pl1_post = sym | val; param->ir_ll = pwm_acts_ir_get_len(protocol_param->ir_lc_code); param->ir_ld = protocol_param->ir_lc_code;//01b if(protocol & PWM_IR_CYCLE_MODE) { ld_len = pwm_acts_ir_get_len(protocol_param->ir_trc_loc); param->ir_pl = (loc == 1)?(protocol_param->ir_dc_length - ld_len):(ld_len -1); param->ir_asc = protocol_param->ir_asc; param->ir_Tf = (loc == 1)? 0 : (protocol_param->ir_Tf_length + PWM_IR_TX_MARGIN) * 10; val = ir_code_pos_val(protocol_param->ir_0_code) * protocol_param->code_bit_length; val = val * cr_rate/1000; if(protocol_param->ir_stop_bit && loc != 1) param->ir_lc = param->ir_lc - val; } else { param->ir_pl = protocol_param->ir_dc_length; param->ir_asc = protocol_param->ir_asc; param->ir_Tf = (protocol_param->ir_Tf_length + PWM_IR_TX_MARGIN) * 10; } param->ir_stop_bit = protocol_param->ir_stop_bit; } static void pwm_acts_ir_param_cal(struct ir_tx_data_param *ctrl, struct pwm_ir_mode_param_t *result, struct ir_tx_protocol_param *protocol_param) { u32_t num_0, num_1, sum_cycle, ir_sl, pwm_rate, mode, ld_len; u32_t data[2] = {0}; struct pwm_ir_mode_param_t param; mode = ctrl->mode & PWM_IR_MASK; pwm_acts_ir_param_sw(ctrl, &param , 1, protocol_param); pwm_rate = pwm_clk_rate/1000/param.ir_period; result[0].ir_period = param.ir_period; result[0].ir_duty = param.ir_duty; result[0].ir_lc = param.ir_lc; result[0].ir_pl0_pre = param.ir_pl0_pre; result[0].ir_pl0_post = param.ir_pl0_post; result[0].ir_pl1_pre = param.ir_pl1_pre; result[0].ir_pl1_post = param.ir_pl1_post; result[0].ir_ll = param.ir_ll; result[0].ir_ld = param.ir_ld;//01b if(param.ir_stop_bit) { param.ir_pl = param.ir_pl + 1;//patload 24bit+endflag ctrl->data[1] = (ctrl->data[1] << 1) | (ctrl->data[0] >> 31); ctrl->data[0] = ctrl->data[0] << 1; } ld_len = pwm_acts_ir_get_len(protocol_param->ir_trc_loc); data[0] = ctrl->data[0] >> ld_len; data[1] = ctrl->data[1] >> ld_len; result[0].ir_pl = param.ir_pl; if(param.ir_pl > 32) { result[0].ir_pd0 = data[0]; num_1 = pwm_acts_data_cal(data[0], 32); result[0].ir_pd1 = data[1]; num_1 += pwm_acts_data_cal(data[0], result[0].ir_pl - 32); } else { result[0].ir_pd0 = data[0]; num_1 = pwm_acts_data_cal(data[0], result[0].ir_pl); } num_0 = result[0].ir_pl - num_1; sum_cycle = result[0].ir_lc*result[0].ir_ll; sum_cycle += num_0*((result[0].ir_pl0_pre&0xff) + (result[0].ir_pl0_post&0xff)); sum_cycle += num_1*((result[0].ir_pl1_pre&0xff) + (result[0].ir_pl1_post&0xff)); if(param.ir_Tf) { ir_sl = (param.ir_Tf/1000 - (sum_cycle/pwm_rate)); ir_sl = ir_sl * pwm_rate / result[0].ir_lc; result[0].ir_sl = ir_sl; } else result[0].ir_sl = 0; if(ctrl->buf_num > 1 && (ctrl->mode & PWM_IR_CYCLE_MODE)) result[0].ir_asc = param.ir_asc * 2; else if(ctrl->buf_num > 1) result[0].ir_asc = param.ir_asc + 1; else result[0].ir_asc = param.ir_asc; if(ctrl->buf_num > 1) { if(ctrl->mode & PWM_IR_CYCLE_MODE) pwm_acts_ir_param_sw(ctrl, &param, 2, protocol_param); else pwm_acts_ir_param_sw(ctrl, &param, 2, protocol_param + 1); result[1].ir_lc = param.ir_lc; if(ctrl->lead == NULL) { result[1].ir_ld = param.ir_ld; result[1].ir_ll = param.ir_ll; } else { result[1].ir_ld = ctrl->lead->ld; result[1].ir_ll = ctrl->lead->ll; } if(param.ir_stop_bit) param.ir_pl = param.ir_pl + 1;//patload 24bit+endflag result[1].ir_pl = param.ir_pl; data[0] = data[1] = 0; ld_len = (1 << ld_len) - 1; data[0] = ctrl->data[0] & ld_len; data[1] = ctrl->data[1] & ld_len; if(param.ir_pl > 32) { result[1].ir_pd0 = data[0]; num_1 = pwm_acts_data_cal(data[0], 32); result[1].ir_pd1 = data[1]; num_1 += pwm_acts_data_cal(data[0], result[1].ir_pl - 32); } else { result[1].ir_pd0 = data[0]; num_1 = pwm_acts_data_cal(data[0], result[1].ir_pl); } result[1].ir_sl = 0; num_0 = result[1].ir_pl - num_1; if(ctrl->mode & PWM_IR_CYCLE_MODE) sum_cycle += param.ir_lc * result[1].ir_ll; else sum_cycle = param.ir_lc * result[1].ir_ll; sum_cycle += num_0*((param.ir_pl0_pre&0xff) + (param.ir_pl0_post&0xff)); sum_cycle += num_1*((param.ir_pl1_pre&0xff) + (param.ir_pl1_post&0xff)); if(param.ir_Tf) { ir_sl = (param.ir_Tf/1000 - (sum_cycle/pwm_rate)); ir_sl = ir_sl * pwm_rate / param.ir_lc; result[1].ir_sl = ir_sl; } } result[0].buf_num = ctrl->buf_num; result[0].mode = ctrl->mode; } static int pwm_acts_ir_transfer(const struct device *dev, u32_t pwm, pwm_ir_ctrl_t *ctrl) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; uint32_t base, group; u16_t status; struct pwm_ir_mode_param_t result[2] = {0}; struct ir_tx_protocol_param *ir_protocol = ctrl->protocol; struct ir_tx_data_param *ir_data = ctrl->data; k_sem_take(&data->ir_transfer_sync, K_FOREVER); data->ir_event_timeout = ir_protocol->ir_lc_bit_length; pwm_acts_ir_param_cal(ir_data, result, ir_protocol); group = pwm_acts_get_group(pwm); status = data->group_init_status[group]; if((status&PWM_MODE_MASK) != PWM_IR_INIT && (status&PWM_MODE_MASK) != PWM_DEFAULT_REG) {//not ir mode or default LOG_ERR("start a ir mode but have not stop this group bfore!"); return -EINVAL; } pwm = (pwm > 5)?pwm-6:pwm; pwm = (pwm > 5)?pwm-4-group:pwm; base = pwm_acts_get_reg_base(cfg->base, group); if(group == PWM_GROUP5_REG) {//only group 5 support ir pwm_acts_ir_tx(cfg, data, pwm, result, base); } else { LOG_ERR("unsuported channel: %d",pwm); return -EINVAL; } data->group_init_status[group] = PWM_IR_INIT | PWM_chan(pwm) | status; return 0; } static int pwm_acts_ir_stop_transfer(const struct device *dev) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; struct acts_pwm_ir *pwm_ir = (struct acts_pwm_ir *)PWM_IR(cfg->base); if (pwm_ir->ir_ctl & PWM_IRCTL_START) { data->manual_stop_flag = true; pwm_ir->ir_ctl |= PWM_IRCTL_STOP; } k_sem_take(&data->ir_sync, K_FOREVER); k_sem_give(&data->ir_transfer_sync); return 0; } #ifdef CONFIG_PWM_TAI_FULL_FUNC static int pwm_acts_pin_stop(const struct device *dev, uint32_t pwm) { return 0; } #endif static int pwm_acts_pin_repeat(const struct device *dev, uint32_t pwm, uint8_t repeat) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; uint32_t base,group; u16_t status; unsigned int key; if(repeat == 0) return -EINVAL; key = irq_lock(); group = pwm_acts_get_group(pwm); status = data->group_init_status[group]; pwm = (pwm > 5)?pwm-6:pwm; pwm = (pwm > 5)?pwm-4-group:pwm; base = pwm_acts_get_reg_base(cfg->base, group); switch(group){ case PWM_GROUP0_REG: sys_write32(PWM_INTCTL_G0REPEAT, PWM_INT_CTL(cfg->base)); break; case PWM_GROUP1_REG: sys_write32(PWM_INTCTL_G1REPEAT, PWM_INT_CTL(cfg->base)); break; case PWM_GROUP2_REG: sys_write32(PWM_INTCTL_G2C0 | PWM_INTCTL_G2REPEAT, PWM_INT_CTL(cfg->base)); break; case PWM_GROUP3_REG: sys_write32(PWM_INTCTL_G3C0 | PWM_INTCTL_G3REPEAT, PWM_INT_CTL(cfg->base)); break; case PWM_GROUP4_REG: sys_write32(PWM_INTCTL_G4C0 | PWM_INTCTL_G4REPEAT, PWM_INT_CTL(cfg->base)); break; case PWM_GROUP5_REG: sys_write32(PWM_INTCTL_G5C0 | PWM_INTCTL_G5REPEAT, PWM_INT_CTL(cfg->base)); break; default: return -EINVAL; } struct acts_pwm_groupx *pwm_reg = (struct acts_pwm_groupx *)base; pwm_reg->repeat = repeat; pwm_reg->ctrl |= PWMx_CTRL_HUA; // k_sleep(K_USEC(32)); // pwm_reg->ctrl |= PWMx_CTRL_CU; sys_write32(0xffffffff, PWM_PENDING(cfg->base)); irq_unlock(key); return 0; } /* * Get the clock rate (cycles per second) for a PWM pin. * * Parameters * dev: Pointer to PWM device structure * pwm: PWM port number * cycles: Pointer to the memory to store clock rate (cycles per second) * * return 0, or negative errno code */ #ifdef CONFIG_PWM_TAI_FULL_FUNC static int pwm_acts_get_cycles_per_sec(const struct device *dev, uint32_t pwm, u64_t *cycles) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; u32_t group; group = pwm_acts_get_group(pwm); if(group == PWM_GROUP5_REG) *cycles = pwm_clk_rate; else *cycles = pwm_normal_clk_rate; return 0; } #endif static int pwm_acts_reset_peripheral(int reset_id) { sys_write32((sys_read32(RMU_MRCR0) & ~(0x3f << reset_id)), RMU_MRCR0); sys_write32(((0x3f << reset_id) | sys_read32(RMU_MRCR0)), RMU_MRCR0); return 0; } static int pwm_acts_ir_tx_power(const struct device *dev, uint8_t level) { struct pwm_acts_data *data = dev->data; if(level > 7) { LOG_ERR("error param level:%d", level); return -1; } data->ir_pout = level; return 0; } int pwm_acts_init(const struct device *dev) { const struct pwm_acts_config *cfg = dev->config; struct pwm_acts_data *data = dev->data; acts_pinmux_setup_pins(cfg->pinmux, cfg->pinmux_size - 1); /* reset pwm controller */ pwm_acts_reset_peripheral(cfg->reset_id); cfg->irq_config_func(); for(int i = 0;i < 5;i++) { /* enable pwm controller clock */ acts_clock_peripheral_enable(cfg->clock_id + i); /* 32kHZ */ pwm_acts_set_clk(cfg, i, pwm_normal_clk_rate); } acts_clock_peripheral_enable(cfg->clock_id + 5); pwm_acts_set_clk(cfg, 5, pwm_clk_rate);//pwm_normal_clk_rate);// memset(data->group_init_status, 0 ,6); k_sem_init(&data->ir_sync, 0, 1); k_sem_init(&data->ir_transfer_sync, 0, 1); k_sem_give(&data->ir_transfer_sync); if (cfg->dma_dev_name != NULL) { data->dma_dev = (struct device *)device_get_binding(cfg->dma_dev_name); if (!data->dma_dev) { LOG_ERR("Bind DMA device %s error", cfg->dma_dev_name); return -ENOENT; } k_sem_init(&data->dma_sync, 0, 1); data->dma_chan = dma_request(data->dma_dev, 0xff); if(data->dma_chan < 0){ LOG_ERR("dma-dev rxchan config err chan=%d\n", data->dma_chan); return -ENODEV; } } data->ir_pout = 0; data->manual_stop_flag = false; k_timer_init(&data->timer, pwm_acts_ir_timeout_event, NULL); k_timer_user_data_set(&data->timer, (void *)data); return 0; } const struct pwm_driver_api pwm_acts_driver_api = { .pin_set = pwm_acts_pin_set, .ir_transfer = pwm_acts_ir_transfer, .ir_stop_transfer = pwm_acts_ir_stop_transfer, .pin_repeat = pwm_acts_pin_repeat, .ir_tx_power_set = pwm_acts_ir_tx_power, #ifdef CONFIG_PWM_TAI_FULL_FUNC .get_cycles_per_sec = pwm_acts_get_cycles_per_sec, .set_breath = pwm_acts_set_breath_mode, .set_program = pwm_acts_set_program_mode, .pin_stop = pwm_acts_pin_stop, #endif }; static struct pwm_acts_data pwm_acts_data; static const struct acts_pin_config pins_pwm[] = {CONFIG_PWM_MFP}; static void pwm_acts_irq_config(void); static const struct pwm_acts_config pwm_acts_config = { .base = PWM_REG_BASE, .cycle = CONFIG_PWM_CYCLE, .clock_id = CLOCK_ID_PWM0, .reset_id = RESET_ID_PWM0, .dma_dev_name = CONFIG_DMA_0_NAME, .txdma_id = CONFIG_PWM_DMA_ID, .pinmux = pins_pwm, .irq_config_func = pwm_acts_irq_config, .pinmux_size = ARRAY_SIZE(pins_pwm), }; #if CONFIG_PWM static void pwm_acts_pinmux_setup_pins(const struct acts_pin_config *pinconf, int pins, u8_t flag) { int i; for (i = 0; i < pins; i++) { if(flag) acts_pinmux_set(pinconf[i].pin_num, pinconf[i].mode); else acts_pinmux_set(pinconf[i].pin_num, 0x1000); } } static int pwm_acts_active(const struct device *dev) { const struct pwm_acts_config *cfg = dev->config; pwm_acts_pinmux_setup_pins(cfg->pinmux, cfg->pinmux_size - 1, 1); pwm_acts_reset_peripheral(cfg->reset_id); cfg->irq_config_func(); for(int i = 0;i < 5;i++) { acts_clock_peripheral_enable(cfg->clock_id + i); pwm_acts_set_clk(cfg, i, pwm_normal_clk_rate); } acts_clock_peripheral_enable(cfg->clock_id + 5); pwm_acts_set_clk(cfg, 5, pwm_clk_rate);//pwm_normal_clk_rate);// return 0; } static int pwm_acts_suspend(const struct device *dev) { struct pwm_acts_data *data = dev->data; const struct pwm_acts_config *cfg = dev->config; u16_t status; for(int i = 0; i < PWM_GROUP_MAX; i++) { status = data->group_init_status[i] & PWM_MODE_MASK; if((status != PWM_DEFAULT_REG) &&(status != PWM_FIX_INIT)) { return -ESRCH; } status = data->group_init_status[i]; if((PWM_FIX_INIT == (status & PWM_MODE_MASK)) && ((status & PWM_chan_act_MASK) != 0)) { return -ESRCH; } } pwm_acts_pinmux_setup_pins(cfg->pinmux, cfg->pinmux_size, 0); memset(data->group_init_status, 0 ,6); sys_write32((sys_read32(RMU_MRCR0) & ~(0x3f << cfg->reset_id)), RMU_MRCR0); for(int i = 0; i < PWM_GROUP_MAX; i++) acts_clock_peripheral_disable(cfg->clock_id + i); return 0; } static int pwm_acts_pm_control(const struct device *dev, uint32_t command, void *context, device_pm_cb cb, void *arg) { int ret = 0; uint32_t state = *((uint32_t*)context); static u8_t sleep_status = 1; LOG_DBG("command:0x%x state:%d", command, state); if (command != DEVICE_PM_SET_POWER_STATE) return 0; switch (state) { case DEVICE_PM_ACTIVE_STATE: if(sleep_status == 0) pwm_acts_active(dev); sleep_status = 1; break; case DEVICE_PM_SUSPEND_STATE: ret = pwm_acts_suspend(dev); if(ret == 0) sleep_status = 0; break; case DEVICE_PM_EARLY_SUSPEND_STATE: case DEVICE_PM_LATE_RESUME_STATE: case DEVICE_PM_LOW_POWER_STATE: case DEVICE_PM_OFF_STATE: break; default: ret = -ESRCH; } return ret; } DEVICE_DEFINE(pwm_acts, CONFIG_PWM_NAME, pwm_acts_init, pwm_acts_pm_control, &pwm_acts_data, &pwm_acts_config, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &pwm_acts_driver_api); static void pwm_acts_irq_config(void) { IRQ_CONNECT(IRQ_ID_PWM, CONFIG_PWM_IRQ_PRI, pwm_acts_isr, DEVICE_GET(pwm_acts), 0); irq_enable(IRQ_ID_PWM); //IRQ_CONNECT(IRQ_ID_KEY_WAKEUP, 1, // mxkeypad_acts_wakeup_isr, DEVICE_GET(mxkeypad_acts), 0); } #endif请记住上面的代码
06-24
#include "ina3221.h" #define INA3221_CFG_REG 0x00 //配置寄存器 #define INA3221_CH1SHUNT_REG 0x01 //通道 1 分流电压 #define INA3221_CH1BUS_REG 0x02 //通道 1 总线电压 #define INA3221_CH2SHUNT_REG 0x03 //通道 2 分流电压 #define INA3221_CH2BUS_REG 0x04 //通道 2 总线电压 #define INA3221_CH3SHUNT_REG 0x05 //通道 3 分流电压 #define INA3221_CH3BUS_REG 0x06 //通道 3 总线电压 #define INA3221_CH1CAL_REG 0x07 //通道 1 严重警报限制 #define INA3221_CH1WAL_REG 0x08 //通道 1 警告警报限制 #define INA3221_CH2CAL_REG 0x09 //通道 2 严重警报限制 #define INA3221_CH2WAL_REG 0x0A //通道 2 警告警报限制 #define INA3221_CH3CAL_REG 0x0B //通道 3 严重警报限制 #define INA3221_CH3WAL_REG 0x0C //通道 3 警告警报限制 #define INA3221_SVS_REG 0x0D //分流电压和 #define INA3221_SVSLIMIT_REG 0x0E //分流电压和限制 #define INA3221_ME_REG 0x0F //屏蔽/启用 警报 #define INA3221_PVUPPER_REG 0x10 //功率有效上限 #define INA3221_PVLOW_REG 0x11 //功率有效下限 #define INA3221_MANUID_REG 0xFE //制造商标识号 #define INA3221_DIEID_REG 0xFF //模具标识号 #define INA3221_MANU_ID 0x5449 //唯一制造商标识号 #define INA3221_DIE_ID 0x3220 //唯一模具标识号 /** ******************************************************************************* * @brief 设定采集的样本数量并一起取平均值 * @note - 0 : 1 (采样次数) * @note - 1 : 4 (采样次数) * @note - 2 : 16 (采样次数) * @note - 3 : 64 (采样次数) * @note - 4 : 128 (采样次数) * @note - 5 : 256 (采样次数) * @note - 6 : 512 (采样次数) * @note - 7 : 1024 (采样次数) ******************************************************************************* */ uint8_t CFG_AVG = 2; /** ******************************************************************************* * @brief 总线电压测量设定转换时间 * @note - 0 : 140us * @note - 1 : 204us * @note - 2 : 332us * @note - 3 : 588us * @note - 4 : 1.1ms * @note - 5 : 2.116ms * @note - 6 : 4.156ms * @note - 7 : 8.244ms ******************************************************************************* */ uint8_t CFG_VbusCT = 5; /** ******************************************************************************* * @brief 为分流电压测量设定转换时间 * @note - 0 : 140us * @note - 1 : 204us * @note - 2 : 332us * @note - 3 : 588us * @note - 4 : 1.1ms * @note - 5 : 2.116ms * @note - 6 : 4.156ms * @note - 7 : 8.244ms ******************************************************************************* */ uint8_t CFG_VshCT = 5; /** ******************************************************************************* * @brief 选择连续的、 触发的、 或者省电运行模式 * @note - 0 : 省电 * @note - 1 : 分流电压、触发模式 * @note - 2 : 总线电压、触发模式 * @note - 3 : 分流和总线电压、触发模式 * @note - 4 : 省电 * @note - 5 : 分流电压、持续模式 * @note - 6 : 总线电压、持续模式 * @note - 7 : 分流和总线电压、持续模式 ******************************************************************************* */ uint8_t CFG_Mode = 7; /************************模拟IIC接口****************************/ void INA3221_IIC_Start(void) { my_I2C_SDA_H; my_I2C_SCL_H; delay_us(5); my_I2C_SDA_L; // START:when CLK is high,DATA change form high to low delay_us(5); my_I2C_SCL_L; //钳住I2C总线,准备发送或接收数据 delay_us(5); } void INA3221_IIC_Stop(void) { my_I2C_SDA_L; // STOP:when CLK is high DATA change form low to high delay_us(5); my_I2C_SCL_H; delay_us(5); my_I2C_SDA_H; //发送I2C总线结束信号 delay_us(5); } void INA3221_IIC_Ack(void) { my_I2C_SDA_L; delay_us(5); my_I2C_SCL_H; delay_us(5); my_I2C_SCL_L; delay_us(5); my_I2C_SDA_H; } void INA3221_IIC_NAck(void) { my_I2C_SDA_H; delay_us(5); my_I2C_SCL_H; delay_us(5); my_I2C_SCL_L; delay_us(5); my_I2C_SDA_L; } uint8_t INA3221_IIC_Wait_Ack(void) { uint8_t ucErrTime = 0; my_I2C_SDA_H; my_SDA_IN(); // SDA设置为输入 delay_us(5); my_I2C_SCL_H; delay_us(5); while (my_READ_SDA()) { ucErrTime++; if (ucErrTime > 250) { INA3221_IIC_Stop(); return 1; } } my_I2C_SCL_L; //时钟输出0 my_SDA_OUT(); // SDA设置为输入 return 0; } void INA3221_IIC_Send_Byte(uint8_t txd) { my_I2C_SCL_L; //拉低时钟开始数据传输 for (uint8_t i = 0; i < 8; i++) { if (txd & 0x80) my_I2C_SDA_H; else my_I2C_SDA_L; txd <<= 1; my_I2C_SCL_H; delay_us(5); my_I2C_SCL_L; delay_us(5); } } uint8_t INA3221_IIC_Read_Byte(unsigned char ack) { uint8_t TData = 0, i; my_SDA_IN(); // SDA设置为输入 for (i = 0; i < 8; i++) { my_I2C_SCL_H; delay_us(5); TData = TData << 1; // if(GPIOB->IDR& GPIO_IDR_IDR7) //判断SDA是否为高 if (my_READ_SDA()) { TData |= 0x01; } my_I2C_SCL_L; delay_us(5); } my_SDA_OUT(); // SDA设置为输出 if (!ack) INA3221_IIC_NAck(); else INA3221_IIC_Ack(); return TData; } void INA3221_SendData(uint8_t addr, uint8_t reg, uint16_t data) { uint8_t temp = 0; INA3221_IIC_Start(); INA3221_IIC_Send_Byte(addr); INA3221_IIC_Wait_Ack(); INA3221_IIC_Send_Byte(reg); INA3221_IIC_Wait_Ack(); temp = (uint8_t)(data >> 8); INA3221_IIC_Send_Byte(temp); INA3221_IIC_Wait_Ack(); temp = (uint8_t)(data & 0x00FF); INA3221_IIC_Send_Byte(temp); INA3221_IIC_Wait_Ack(); INA3221_IIC_Stop(); } void INA3221_SetRegPointer(uint8_t addr, uint8_t reg) { INA3221_IIC_Start(); INA3221_IIC_Send_Byte(addr); INA3221_IIC_Wait_Ack(); INA3221_IIC_Send_Byte(reg); INA3221_IIC_Wait_Ack(); INA3221_IIC_Stop(); } uint16_t INA3221_ReadData(uint8_t addr) { uint16_t temp = 0; INA3221_IIC_Start(); INA3221_IIC_Send_Byte(addr + 1); INA3221_IIC_Wait_Ack(); temp = INA3221_IIC_Read_Byte(1); temp <<= 8; temp |= INA3221_IIC_Read_Byte(0); INA3221_IIC_Stop(); return temp; } /** * @description: INA3221自检 * @param {uint8_t} addr * @return {*} */ void INA3221_SelfCheck(uint8_t addr) { uint16_t id = 0; while (id != INA3221_DIE_ID) { // delay_ms(50); //卡这说明硬件连接异常或者是地址错误 INA3221_SetRegPointer(addr, INA3221_DIEID_REG); id = INA3221_ReadData(addr); } } /********************************应用部分****************************************/ /** * @description: INA3221初始化 * @return {*} */ void INA3221_Init(void) { //I2C初始化 //引脚初始化 //芯片初始化 INA3221_SendData(INA3221_ADDR1, INA3221_CFG_REG, 0x8000); //软件复位 INA3221_SendData(INA3221_ADDR2, INA3221_CFG_REG, 0x8000); //软件复位 delay_ms(10); // 配置寄存器设置控制三个输入通道的分流和总线电压测量的工作模式。 // 该寄存器控制分流和总线电压测量的转换时间设置以及使用的平均模式。 // 配置寄存器用于独立启用或禁用每个通道,以及选择控制选择要测量的信号的操作模式。 // 详见数据手册P26 unsigned short cfg_reg_value = 0x7000|(CFG_AVG<<9)|(CFG_VbusCT<<6)|(CFG_VshCT<<3)|CFG_Mode; INA3221_SendData(INA3221_ADDR1, INA3221_CFG_REG, cfg_reg_value); // 7127为默认配置 INA3221_SendData(INA3221_ADDR2, INA3221_CFG_REG, cfg_reg_value); // 7127为默认配置 } /** * @description: 获取电压 * @param {uint8_t} addr * @param {uint8_t} channel 通道编号(1\2\3) * @return {uint16_t} 通道所对应的电压 */ uint16_t INA3221_GetVoltage(uint8_t addr, uint8_t channel) { uint32_t temp = 0; switch (channel) { case 1: INA3221_SetRegPointer(addr, INA3221_CH1BUS_REG); break; case 2: INA3221_SetRegPointer(addr, INA3221_CH2BUS_REG); break; case 3: INA3221_SetRegPointer(addr, INA3221_CH3BUS_REG); break; default: break; } temp = INA3221_ReadData(addr); if (temp & 0x8000) temp = ~(temp - 1); return (uint16_t)temp; } /** * @description: 获取分流电压 * @param {uint8_t} addr ina3221的IIC地址 * @param {uint8_t} channel 通道编号(1\2\3) * @return {uint16_t} 通道的分流电压 */ uint16_t INA3221_GetShuntVoltage(uint8_t addr, uint8_t channel) { uint32_t temp = 0; switch (channel) { case 1: INA3221_SetRegPointer(addr, INA3221_CH1SHUNT_REG); break; case 2: INA3221_SetRegPointer(addr, INA3221_CH2SHUNT_REG); break; case 3: INA3221_SetRegPointer(addr, INA3221_CH3SHUNT_REG); break; default: break; } temp = INA3221_ReadData(addr); if (temp & 0x8000) temp = ~(temp - 1); // uint8_t data[2]={0}; // data[0]=temp>>8&0xff; // data[1]=temp&0xff; // RS485_SendData(data,2); return (uint16_t)temp; } /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// //设置电压警告 static void Set_Voltage_Warning(uint8_t ch,uint16_t value) { switch(ch) { case 1:INA3221_SendData(INA3221_ADDR1, INA3221_CH1WAL_REG, value); break; case 2:INA3221_SendData(INA3221_ADDR1, INA3221_CH2WAL_REG, value); break; case 3:INA3221_SendData(INA3221_ADDR1, INA3221_CH3WAL_REG, value); break; case 4:INA3221_SendData(INA3221_ADDR2, INA3221_CH1WAL_REG, value); break; case 5:INA3221_SendData(INA3221_ADDR2, INA3221_CH2WAL_REG, value); break; case 6:INA3221_SendData(INA3221_ADDR2, INA3221_CH3WAL_REG, value); break; } } //设置电压严重报警 static void Set_Voltage_Critical(uint8_t ch,uint16_t value) { switch(ch) { case 1:INA3221_SendData(INA3221_ADDR1, INA3221_CH1CAL_REG, value); break; case 2:INA3221_SendData(INA3221_ADDR1, INA3221_CH2CAL_REG, value); break; case 3:INA3221_SendData(INA3221_ADDR1, INA3221_CH3CAL_REG, value); break; case 4:INA3221_SendData(INA3221_ADDR2, INA3221_CH1CAL_REG, value); break; case 5:INA3221_SendData(INA3221_ADDR2, INA3221_CH2CAL_REG, value); break; case 6:INA3221_SendData(INA3221_ADDR2, INA3221_CH3CAL_REG, value); break; } } //统一设置警告值 void Set_WARNING_CRITICAL(void) { float vcci[6] = {1600/1000.0, 1200/1000.0, 350/1000.0, 350/1000.0, 350/1000.0, 350/1000.0}; uint16_t vi = 0; for(int i=0;i<6;i++) { vi= (uint16_t)(vcci[i]*25/0.04)<<3; Set_Voltage_Warning(i+1,vi);//过压保护 Set_Voltage_Critical(i+1,vi);//过流保护 } } #ifndef __INA3221_H #define __INA3221_H #include "stdint.h" #include "myiic.h" #include "bsp_tmra.h" #include "power.h" #define INA3221_ADDR1 0x80 // A0=GND #define INA3221_ADDR2 0x82 // A0=VS #define INA3221_ADDR3 0x84 // A0=SDA #define INA3221_ADDR4 0x86 // A0=SCL void INA3221_Init(void); uint16_t INA3221_GetVoltage(uint8_t addr, uint8_t channel); uint16_t INA3221_GetShuntVoltage(uint8_t addr, uint8_t channel); void Set_WARNING_CRITICAL(void); #endif#ifndef __INA219_H #define __INA219_H #include "config.h" // I2C Address Options #define INA219_I2C_ADDRESS_CONF_0 (u8)(0x40 << 1) // A0 = GND, A1 = GND #define INA219_I2C_ADDRESS_CONF_1 (u8)(0x41 << 1) // A0 = VS+, A1 = GND #define INA219_I2C_ADDRESS_CONF_2 (u8)(0x42 << 1) // A0 = SDA, A1 = GND #define INA219_I2C_ADDRESS_CONF_3 (u8)(0x43 << 1) // A0 = SCL, A1 = GND #define INA219_I2C_ADDRESS_CONF_4 (u8)(0x44 << 1) // A0 = GND, A1 = VS+ #define INA219_I2C_ADDRESS_CONF_5 (u8)(0x45 << 1) // A0 = VS+, A1 = VS+ #define INA219_I2C_ADDRESS_CONF_6 (u8)(0x46 << 1) // A0 = SDA, A1 = VS+ #define INA219_I2C_ADDRESS_CONF_7 (u8)(0x47 << 1) // A0 = SCL, A1 = VS+ #define INA219_I2C_ADDRESS_CONF_8 (u8)(0x48 << 1) // A0 = GND, A1 = SDA #define INA219_I2C_ADDRESS_CONF_9 (u8)(0x49 << 1) // A0 = VS+, A1 = SDA #define INA219_I2C_ADDRESS_CONF_A (u8)(0x4A << 1) // A0 = SDA, A1 = SDA #define INA219_I2C_ADDRESS_CONF_B (u8)(0x4B << 1) // A0 = SCL, A1 = SDA #define INA219_I2C_ADDRESS_CONF_C (u8)(0x4C << 1) // A0 = GND, A1 = SCL #define INA219_I2C_ADDRESS_CONF_D (u8)(0x4D << 1) // A0 = VS+, A1 = SCL #define INA219_I2C_ADDRESS_CONF_E (u8)(0x4E << 1) // A0 = SDA, A1 = SCL #define INA219_I2C_ADDRESS_CONF_F (u8)(0x4F << 1) // A0 = SCL, A1 = SCL #define INA219_I2C_ADDRESS INA219_I2C_ADDRESS_CONF_0 /*----------------------------------------------------------------------------*/ // Register Addresses #define INA219_REG_CONFIG (u8)(0x00) // CONFIG REGISTER (R/W) #define INA219_REG_SHUNTVOLTAGE (u8)(0x01) // SHUNT VOLTAGE REGISTER (R) #define INA219_REG_BUSVOLTAGE (u8)(0x02) // BUS VOLTAGE REGISTER (R) #define INA219_REG_POWER (u8)(0x03) // POWER REGISTER (R) #define INA219_REG_CURRENT (u8)(0x04) // CURRENT REGISTER (R) #define INA219_REG_CALIBRATION (u8)(0x05) // CALIBRATION REGISTER (R/W) /*----------------------------------------------------------------------------*/ // Macros for assigning config bits #define INA219_CFGB_RESET(x) (u16)((x & 0x01) << 15) // Reset Bit #define INA219_CFGB_BUSV_RANGE(x) (u16)((x & 0x01) << 13) // Bus Voltage Range #define INA219_CFGB_PGA_RANGE(x) (u16)((x & 0x03) << 11) // Shunt Voltage Range #define INA219_CFGB_BADC_RES_AVG(x) (u16)((x & 0x0F) << 7) // Bus ADC Resolution/Averaging #define INA219_CFGB_SADC_RES_AVG(x) (u16)((x & 0x0F) << 3) // Shunt ADC Resolution/Averaging #define INA219_CFGB_MODE(x) (u16) (x & 0x07) // Operating Mode /*----------------------------------------------------------------------------*/ // Configuration Register #define INA219_CFG_RESET INA219_CFGB_RESET(1) // Reset Bit #define INA219_CFG_BVOLT_RANGE_MASK INA219_CFGB_BUSV_RANGE(1) // Bus Voltage Range Mask #define INA219_CFG_BVOLT_RANGE_16V INA219_CFGB_BUSV_RANGE(0) // 0-16V Range #define INA219_CFG_BVOLT_RANGE_32V INA219_CFGB_BUSV_RANGE(1) // 0-32V Range (default) #define INA219_CFG_SVOLT_RANGE_MASK INA219_CFGB_PGA_RANGE(3) // Shunt Voltage Range Mask #define INA219_CFG_SVOLT_RANGE_40MV INA219_CFGB_PGA_RANGE(0) // Gain 1, 40mV Range #define INA219_CFG_SVOLT_RANGE_80MV INA219_CFGB_PGA_RANGE(1) // Gain 2, 80mV Range #define INA219_CFG_SVOLT_RANGE_160MV INA219_CFGB_PGA_RANGE(2) // Gain 4, 160mV Range #define INA219_CFG_SVOLT_RANGE_320MV INA219_CFGB_PGA_RANGE(3) // Gain 8, 320mV Range (default) #define INA219_CFG_BADCRES_MASK INA219_CFGB_BADC_RES_AVG(15) // Bus ADC Resolution and Averaging Mask #define INA219_CFG_BADCRES_9BIT_1S_84US INA219_CFGB_BADC_RES_AVG(0) // 1 x 9-bit Bus sample #define INA219_CFG_BADCRES_10BIT_1S_148US INA219_CFGB_BADC_RES_AVG(1) // 1 x 10-bit Bus sample #define INA219_CFG_BADCRES_11BIT_1S_276US INA219_CFGB_BADC_RES_AVG(2) // 1 x 11-bit Bus sample #define INA219_CFG_BADCRES_12BIT_1S_532US INA219_CFGB_BADC_RES_AVG(3) // 1 x 12-bit Bus sample (default) #define INA219_CFG_BADCRES_12BIT_2S_1MS INA219_CFGB_BADC_RES_AVG(9) // 2 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_4S_2MS INA219_CFGB_BADC_RES_AVG(10) // 4 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_8S_4MS INA219_CFGB_BADC_RES_AVG(11) // 8 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_16S_8MS INA219_CFGB_BADC_RES_AVG(12) // 16 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_32S_17MS INA219_CFGB_BADC_RES_AVG(13) // 32 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_64S_34MS INA219_CFGB_BADC_RES_AVG(14) // 64 x 12-bit Bus samples averaged together #define INA219_CFG_BADCRES_12BIT_128S_68MS INA219_CFGB_BADC_RES_AVG(15) // 128 x 12-bit Bus samples averaged together #define INA219_CFG_SADCRES_MASK INA219_CFGB_SADC_RES_AVG(15) // Shunt ADC Resolution and Averaging Mask #define INA219_CFG_SADCRES_9BIT_1S_84US INA219_CFGB_SADC_RES_AVG(0) // 1 x 9-bit Shunt sample #define INA219_CFG_SADCRES_10BIT_1S_148US INA219_CFGB_SADC_RES_AVG(1) // 1 x 10-bit Shunt sample #define INA219_CFG_SADCRES_11BIT_1S_276US INA219_CFGB_SADC_RES_AVG(2) // 1 x 11-bit Shunt sample #define INA219_CFG_SADCRES_12BIT_1S_532US INA219_CFGB_SADC_RES_AVG(3) // 1 x 12-bit Shunt sample (default) #define INA219_CFG_SADCRES_12BIT_2S_1MS INA219_CFGB_SADC_RES_AVG(9) // 2 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_4S_2MS INA219_CFGB_SADC_RES_AVG(10) // 4 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_8S_4MS INA219_CFGB_SADC_RES_AVG(11) // 8 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_16S_8MS INA219_CFGB_SADC_RES_AVG(12) // 16 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_32S_17MS INA219_CFGB_SADC_RES_AVG(13) // 32 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_64S_34MS INA219_CFGB_SADC_RES_AVG(14) // 64 x 12-bit Shunt samples averaged together #define INA219_CFG_SADCRES_12BIT_128S_68MS INA219_CFGB_SADC_RES_AVG(15) // 128 x 12-bit Shunt samples averaged together #define INA219_CFG_MODE_MASK INA219_CFGB_MODE(7) // Operating Mode Mask #define INA219_CFG_MODE_POWERDOWN INA219_CFGB_MODE(0) // Power-Down #define INA219_CFG_MODE_SVOLT_TRIGGERED INA219_CFGB_MODE(1) // Shunt Voltage, Triggered #define INA219_CFG_MODE_BVOLT_TRIGGERED INA219_CFGB_MODE(2) // Bus Voltage, Triggered #define INA219_CFG_MODE_SANDBVOLT_TRIGGERED INA219_CFGB_MODE(3) // Shunt and Bus, Triggered #define INA219_CFG_MODE_ADCOFF INA219_CFGB_MODE(4) // ADC Off (disabled) #define INA219_CFG_MODE_SVOLT_CONTINUOUS INA219_CFGB_MODE(5) // Shunt Voltage, Continuous #define INA219_CFG_MODE_BVOLT_CONTINUOUS INA219_CFGB_MODE(6) // Bus Voltage, Continuous #define INA219_CFG_MODE_SANDBVOLT_CONTINUOUS INA219_CFGB_MODE(7) // Shunt and Bus, Continuous (default) /*----------------------------------------------------------------------------*/ // Bus Voltage Register #define INA219_BVOLT_CNVR (u16)(0x0002) // Conversion Ready #define INA219_BVOLT_OVF (u16)(0x0001) // Math Overflow Flag struct ina219_value_t { int16 voltage; int32 shunt; int32 current; int32 power; }; extern struct ina219_value_t ina219_value; extern void drv_ina219_init(void); extern int16 ina219_GetBusVoltage_mV(void); extern int32 ina219_GetShuntVoltage_uV(void); extern int32 ina219_GetCurrent_uA(void); extern int32 ina219_GetPower_mW(void); extern void ina219_process(void); #endif #include "INA219.h" #include "config.h" #include "STC32G_Timer.h" #include "STC32G_GPIO.h" #include "STC32G_NVIC.h" #include "STC32G_Exti.h" #include "STC32G_I2C.h" #include "STC32G_Delay.h" #include "STC32G_Switch.h" #if TCFG_DRV_INA219_SUPPORT struct ina219_value_t ina219_value; u16 ina219_calValue = 0; u8 ina219_busVolt_LSB_mV = 4; // Bus Voltage LSB value = 4mV u8 ina219_shuntVolt_LSB_uV = 10; // Shunt Voltage LSB value = 10uV u32 ina219_current_LSB_uA; u32 ina219_power_LSB_mW; void ina219_Write_Register(u8 reg, u16 dat) { u8 val[3]; // ????? + ??(2??) // ??????? val[0] = reg; // ????? val[1] = dat >> 8; // ????? val[2] = dat & 0xFF; // ????? // ??????(??????) I2C_WriteNbyte(INA219_I2C_ADDRESS, val, 3); } void ina219_Read_Register(u8 reg, u16 *dat) { u8 val[2]; // ???????? I2C_WriteNbyte(INA219_I2C_ADDRESS, &reg, 1); // ?????? I2C_ReadNbyte(INA219_I2C_ADDRESS, val, 2); *dat = (val[0] << 8) | val[1]; } // INA219 Set Calibration 16V/16A(Max) 0.02|? void ina219_SetCalibration_16V_16A(void) { u16 configValue; // By default we use a pretty huge range for the input voltage, // which probably isn't the most appropriate choice for system // that don't use a lot of power. But all of the calculations // are shown below if you want to change the settings. You will // also need to change any relevant register settings, such as // setting the VBUS_MAX to 16V instead of 32V, etc. // VBUS_MAX = 16V (Assumes 16V, can also be set to 32V) // VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04) // RSHUNT = 0.02 (Resistor value in ohms) // 1. Determine max possible current // MaxPossible_I = VSHUNT_MAX / RSHUNT // MaxPossible_I = 16A // 2. Determine max expected current // MaxExpected_I = 16A // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit) // MinimumLSB = MaxExpected_I/32767 // MinimumLSB = 0.00048 (0.48mA per bit) // MaximumLSB = MaxExpected_I/4096 // MaximumLSB = 0,00390 (3.9mA per bit) // 4. Choose an LSB between the min and max values // (Preferrably a roundish number close to MinLSB) // CurrentLSB = 0.00050 (500uA per bit) // 5. Compute the calibration register // Cal = trunc (0.04096 / (Current_LSB * RSHUNT)) // Cal = 4096 (0x1000) // ina219_calValue = 0x1000; ina219_calValue = 0x1000; //0x1000; // 6. Calculate the power LSB // PowerLSB = 20 * CurrentLSB // PowerLSB = 0.01 (10mW per bit) // 7. Compute the maximum current and shunt voltage values before overflow // // Max_Current = Current_LSB * 32767 // Max_Current = 16.3835A before overflow // // If Max_Current > Max_Possible_I then // Max_Current_Before_Overflow = MaxPossible_I // Else // Max_Current_Before_Overflow = Max_Current // End If // // Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT // Max_ShuntVoltage = 0.32V // // If Max_ShuntVoltage >= VSHUNT_MAX // Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX // Else // Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage // End If // 8. Compute the Maximum Power // MaximumPower = Max_Current_Before_Overflow * VBUS_MAX // MaximumPower = 1.6 * 16V // MaximumPower = 256W // Set multipliers to convert raw current/power values ina219_current_LSB_uA = 100; // Current LSB = 500uA per bit ina219_power_LSB_mW = 2; // Power LSB = 10mW per bit = 20 * Current LSB // Set Calibration register to 'Cal' calculated above ina219_Write_Register(INA219_REG_CALIBRATION, ina219_calValue); // Set Config register to take into account the settings above configValue = ( INA219_CFG_BVOLT_RANGE_16V | INA219_CFG_SVOLT_RANGE_320MV | INA219_CFG_BADCRES_12BIT_16S_8MS | INA219_CFG_SADCRES_12BIT_16S_8MS | INA219_CFG_MODE_SANDBVOLT_CONTINUOUS ); // configValue = ( INA219_CFG_BVOLT_RANGE_16V | INA219_CFG_SVOLT_RANGE_320MV | INA219_CFG_BADCRES_12BIT_32S_17MS | INA219_CFG_SADCRES_12BIT_32S_17MS | INA219_CFG_MODE_SANDBVOLT_CONTINUOUS ); ina219_Write_Register(INA219_REG_CONFIG, configValue); } void ina219_configureRegisters(void) { delay_ms(15); ina219_SetCalibration_16V_16A(); } int16 ina219_GetBusVoltage_raw(void) { int16 val; ina219_Read_Register(INA219_REG_BUSVOLTAGE, (u16*)&val); val >>= 3; // Shift to the right 3 to drop CNVR and OVF return (val); } int16 ina219_GetCurrent_raw(void) { int16 val; // Sometimes a sharp load will reset the INA219, which will // reset the cal register, meaning CURRENT and POWER will // not be available ... avoid this by always setting a cal // value even if it's an unfortunate extra step ina219_Write_Register(INA219_REG_CALIBRATION, ina219_calValue); // Now we can safely read the CURRENT register! ina219_Read_Register(INA219_REG_CURRENT, (u16*)&val); return (val); } int16 ina219_GetBusVoltage_mV(void) { int16 val; ina219_Read_Register(INA219_REG_BUSVOLTAGE, (u16*)&val); val >>= 3; // Shift to the right 3 to drop CNVR and OVF val *= ina219_busVolt_LSB_mV; // multiply by LSB(4mV) return (int16)(val); } int32 ina219_GetShuntVoltage_uV(void) { int32 val; int16 reg; ina219_Read_Register(INA219_REG_SHUNTVOLTAGE, (u16*)&reg); val = (int32)reg * ina219_shuntVolt_LSB_uV; // multiply by LSB(10uV) return (int32)val; } int32 ina219_GetCurrent_uA(void) { int32 val; int16 reg; // Sometimes a sharp load will reset the INA219, which will // reset the cal register, meaning CURRENT and POWER will // not be available ... avoid this by always setting a cal // value even if it's an unfortunate extra step ina219_Write_Register(INA219_REG_CALIBRATION, ina219_calValue); // Now we can safely read the CURRENT register! ina219_Read_Register(INA219_REG_CURRENT, (u16*)&reg); val = (int32)reg * ina219_current_LSB_uA; return (int32)(val); } int32 ina219_GetPower_mW(void) { int32 val; int16 reg; // Sometimes a sharp load will reset the INA219, which will // reset the cal register, meaning CURRENT and POWER will // not be available ... avoid this by always setting a cal // value even if it's an unfortunate extra step ina219_Write_Register(INA219_REG_CALIBRATION, ina219_calValue); // Now we can safely read the POWER register! ina219_Read_Register(INA219_REG_POWER, (u16*)&reg); val = (int32)reg * ina219_power_LSB_mW; return (int32)(val); } void ina219_process(void) { // TODO: ???? Vin-?GND????? ina219_value.voltage = ina219_GetBusVoltage_mV(); // TODO: ???????? ina219_value.shunt = ina219_GetShuntVoltage_uV(); // TODO: ?? ina219_value.current = ina219_GetCurrent_uA(); ina219_value.power = ina219_GetPower_mW(); } void drv_ina219_init(void) { I2C_InitTypeDef i2c; i2c.I2C_Enable = ENABLE; i2c.I2C_Mode = I2C_Mode_Master; i2c.I2C_Speed = MAIN_Fosc/2/(100000*2+4); i2c.I2C_MS_WDTA = DISABLE; i2c.I2C_SL_MA = ENABLE; I2C_Init(&i2c); // NVIC_I2C_Init(I2C_Mode_Master, ENABLE, Priority_1); // I2C Master???????? P2_MODE_IO_PU(GPIO_Pin_4); P2_MODE_IO_PU(GPIO_Pin_5); I2C_SW(I2C_P24_P25); ina219_configureRegisters(); } #endif 参考INA3221这份示例,把我的INA219驱动改成驱动INA3221的
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值