1403|2

25

帖子

0

TA的资源

一粒金砂(中级)

【雅特力AT-START-F435】ADC软触发always、DACTmr2触发、DMA,驱动LED被钳位1.54V问题 [复制链接]

本帖最后由 zhangbaoyin 于 2023-6-19 11:50 编辑

【雅特力AT-START-F435】ADC软件触发always、DACTmr2触发、DMA,驱动LED被钳位1.54V问题

 

目的:

  • 使用PB0采样电压,采样结束产生DMA请求,DMA将数据搬移到变量adc1_ordinary_valuetab中
  • 使用PA4输出采样电压,杜邦线连接到PD13驱动LED2,实现电压随动

 

解决的问题:

  • 使用Demo,直接从ADC搬移的数值放入DAC寄存器数值错误
  • DMA的8bit数据寄存器和12bit数据寄存器不相同,小心搬移错误
  • 不开启DxOBDIS输出增益,会导致驱动LED最低1.54V问题

一、初始化ADC

  • 初始化ADC的GPIO-PB0。设置为模拟输入
/**
	* [url=home.php?mod=space&uid=159083]@brief[/url]   PB0 ADC-GPIO configuration.
	*
	*/
void gpio_config(void)
{
  gpio_init_type gpio_initstructure;
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

  gpio_default_para_init(&gpio_initstructure);

  /* config adc pin as analog input mode */
  gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
  gpio_initstructure.gpio_pins = GPIO_PINS_0;
  gpio_init(GPIOB, &gpio_initstructure);
}
  • 配置DMA。
  1. 使用DMA1-CH1,开启DMA1-CH1的NVIC中断(DMA1_Channel1_IRQn),用于记录DMA搬移成功的次数,也就是计算采样率(具体计算采样率的代码在下一节)
  2. buffer_size:DMA的一次搬移数据个数,就一个ADC通道,采用一个数据就好
  3. direction:由ADC到内存,为DMA_DIR_PERIPHERAL_TO_MEMORY(外设到内存)
  4. memory_base_addr为内存地址,设置为一个数组就好,然后传入数组首地址,并将地址转化为 (uint32_t) 类型,而不是 (* uint32_t) 的指针类型
  5. 因为使用的是12bitADC采样,所以DMA传输宽度使用WIDTH_HALFWORD(16bit半字宽度)
  6. 外设和内存自动地址增加设置为FALSE
  7. 将ADC通道的DMA的优先级设置为高(DAC设置为中,以ADC为主,DCA为次)
/**
  * @brief  dma configuration.
  * @param  none
  * @retval none
  */
void dma_config(void)
{
  dma_init_type dma_init_struct;
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
  nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);

  dma_reset(DMA1_CHANNEL1);
  dma_default_para_init(&dma_init_struct);
  dma_init_struct.buffer_size = 1;
  dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
  dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
  dma_init_struct.memory_inc_enable = FALSE;
  dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_HIGH;
  dma_init_struct.loop_mode_enable = TRUE;
  dma_init(DMA1_CHANNEL1, &dma_init_struct);

  dmamux_enable(DMA1, TRUE);
  dmamux_init(DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_ADC1);

  /* enable dma transfer complete interrupt */
  dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
  dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
  • 配置ADC
  1. ADC模式设置为独立模式 ADC_INDEPENDENT_MODE
  2. ADC挂载到HCLK(和CPU同频率),为了使ADC采样速度最大,采用2分频 ADC_HCLK_DIV_2
  3.  common_dma_mode不用配置,在独立模式不起作用
  4. ADC sequence_mode设置为FALSE,不使用序列模式(因为就使用了一个ADC通道)
  5. ADC repeat_mode设置为TRUE,重复模式,就触发一次,然后一直采样
  6. ADC data_align 对齐模式选择为右对齐
  7. ADC ordinary_channel_length 通道个数选择为1个
  8. 配置这个通道的采样顺序,采样时间为92.5个ADC时钟周期
  9. 选择数据寄存器的对齐模式为右对齐
  10. 使能ADC
  11. 使能ADC的DMA请求
  12. 开启ADC
  13. 开启ADC的自校准,并等待校准完成
/**
  * @brief  adc configuration.
  * @param  none
  * @retval none
  */
void adc_config(void)
{
  adc_common_config_type adc_common_struct;
  adc_base_config_type adc_base_struct;
  crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
  nvic_irq_enable(ADC1_2_3_IRQn, 0, 0);

  adc_common_default_para_init(&adc_common_struct);

  /* config combine mode */
  adc_common_struct.combine_mode = ADC_INDEPENDENT_MODE;

  /* config division,adcclk is division by hclk */
  adc_common_struct.div = ADC_HCLK_DIV_2;

  /* config common dma mode,it's not useful in independent mode */
  adc_common_struct.common_dma_mode = ADC_COMMON_DMAMODE_DISABLE;

  /* config common dma request repeat */
  adc_common_struct.common_dma_request_repeat_state = FALSE;

  /* config adjacent adc sampling interval,it's useful for ordinary shifting mode */
  adc_common_struct.sampling_interval = ADC_SAMPLING_INTERVAL_5CYCLES;

  /* config inner temperature sensor and vintrv */
  adc_common_struct.tempervintrv_state = FALSE;

  /* config voltage battery */
  adc_common_struct.vbat_state = FALSE;
  adc_common_config(&adc_common_struct);

  adc_base_default_para_init(&adc_base_struct);

  adc_base_struct.sequence_mode = TRUE;
  adc_base_struct.repeat_mode = TRUE;
  adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
  adc_base_struct.ordinary_channel_length = 1;
  adc_base_config(ADC1, &adc_base_struct);
  adc_resolution_set(ADC1, ADC_RESOLUTION_12B);

  /* config ordinary channel */
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_8, 1, ADC_SAMPLETIME_92_5);

  /* config ordinary trigger source and trigger edge */
  adc_ordinary_conversion_trigger_set(ADC1, ADC_ORDINARY_TRIG_TMR1CH1, ADC_ORDINARY_TRIG_EDGE_NONE);

  /* config dma mode,it's not useful when common dma mode is use */
  adc_dma_mode_enable(ADC1, TRUE);

  /* config dma request repeat,it's not useful when common dma mode is use */
  adc_dma_request_repeat_enable(ADC1, TRUE);

  /* enable adc overflow interrupt */
  adc_interrupt_enable(ADC1, ADC_OCCO_INT, TRUE);

  /* adc enable */
  adc_enable(ADC1, TRUE);
  while(adc_flag_get(ADC1, ADC_RDY_FLAG) == RESET);

  /* adc calibration */
  adc_calibration_init(ADC1);
  while(adc_calibration_init_status_get(ADC1));
  adc_calibration_start(ADC1);
  while(adc_calibration_status_get(ADC1));
}

 

 

二、初始化DAC

  • 初始化GPIO-PA4
  1. 设置为模拟模式
  2. 因为要驱动外设,所以驱动能力选择为强驱动模式GPIO_DRIVE_STRENGTH_STRONGER
  • 选择TMR2作为触发源,触发频率为1kHz
  1. 设置为向上计数模式
  2. 设置计数上限为999(从0开始计数到999经历1000个时钟周期)
  3. TMR2的时钟频率设置为:(systemclock/(systemclock/1000000))/1000 = 1KHz 
  4. 模式选择为 TMR_PRIMARY_SEL_OVERFLOW:tmr primary mode select overflow
  • 配置DAC1 
  1.  DAC1触发选择TMR2 DAC_TMR2_TRGOUT_EVENT
  2. 使能DAC2触发模式
  3. 不启用噪声波
  4. 使能输出增益( dac_output_buffer_enable(DAC1_SELECT, TRUE) ),这个是必须的,不然LED无法驱动
  5. 使能DAC(开启DAC)
  • 配置DMA
  1. 选择DMA通道为DMA1-CH2
  2. buffer_size:DMA的一次搬移数据个数,就一个DAC通道,采用一个数据就好
  3. direction:由ADC到内存,为DMA_DIR_MEMORY_TO_PERIPHERAL(内存到外设)
  4. memory_base_addr为内存地址,设置为一个数组就好,然后传入数组首地址,并将地址转化为 (uint32_t) 类型,而不是 (* uint32_t) 的指针类型
  5. peripheral_base_addr为外设地址:(DAC_BASE+0x008) // DAC1的12位右对齐数据保持寄存器(DAC_D1DTH12R),偏移地址008H
  6. 因为使用的是12bitADC采样,所以DMA传输宽度使用WIDTH_HALFWORD(16bit半字宽度)
  7. 外设和内存自动地址增加设置为FALSE
  8. 将DAC通道的DMA的优先级设置为中(DAC设置为中,以ADC为主,DCA为次)
void DAC_Config(void)
{
  gpio_init_type  gpio_init_struct = {0};
  dma_init_type dma_init_struct;
  crm_clocks_freq_type crm_clocks_freq_struct = {0};
	
  crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DAC_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  /* once the dac is enabled, the corresponding gpio pin is automatically
     connected to the dac converter. in order to avoid parasitic consumption,
     the gpio pin should be configured in analog */
  gpio_init_struct.gpio_pins = GPIO_PINS_4;
  gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init(GPIOA, &gpio_init_struct);

  /* get system clock */
  crm_clocks_freq_get(&crm_clocks_freq_struct);

  /* (systemclock/(systemclock/1000000))/1000 = 1KHz */
  tmr_base_init(TMR2, 999, (crm_clocks_freq_struct.sclk_freq/1000000 - 1));
  tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);

  /* primary tmr2 output selection */
  tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_OVERFLOW);

  /* dac1 configuration */
  dac_trigger_select(DAC1_SELECT, DAC_TMR2_TRGOUT_EVENT);

  dac_trigger_enable(DAC1_SELECT, TRUE);

  dac_wave_generate(DAC1_SELECT, DAC_WAVE_GENERATE_NONE);

  dac_output_buffer_enable(DAC1_SELECT, TRUE);

  dac_dma_enable(DAC1_SELECT, TRUE);

  /* dma1 channel2 configuration */
  dma_reset(DMA1_CHANNEL2);
  dma_init_struct.buffer_size = 1;
  dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
  dma_init_struct.memory_inc_enable = FALSE;
  dma_init_struct.peripheral_base_addr = (uint32_t)(DAC_BASE+0x008);//0x40007410
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  dma_init_struct.loop_mode_enable = TRUE;
  dma_init(DMA1_CHANNEL2, &dma_init_struct);

  /* enable dmamux function */
  dmamux_enable(DMA1, TRUE);
  dmamux_init(DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_DAC1);

  dma_channel_enable(DMA1_CHANNEL2, TRUE);

  /* enable dac1: once the dac1 is enabled, pa.04 is
     automatically connected to the dac converter. */
  dac_enable(DAC1_SELECT, TRUE);

  /* enable tmr2 */
  tmr_counter_enable(TMR2, TRUE);
}

 

 

三、实验效果

    

73eaab0fe346fc91257936516f12e7b1

如果不开启输出增益D1OBDIS使能,DAC的GPIO驱动能力比LED端口的驱动能力,无法抵抗LED的稳压特性,最低电压被钳位在稳压的1.54v。

所以如果要驱动外设,一点要开启输出增益。

最新回复

楼主可以分享一下代码包吗?我想研究一下  详情 回复 发表于 2023-10-13 16:52

回复
举报

6782

帖子

10

TA的资源

版主

所以如果要驱动外设,一点要开启输出增益。

感谢分享经验。


回复

1

帖子

0

TA的资源

一粒金砂(初级)

楼主可以分享一下代码包吗?我想研究一下



回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表