zhangbaoyin

  • 2023-07-09
  • 发表了主题帖: 【雅特力AT-START-F435】SPI显示屏+LVGL库移植

    【雅特力AT-START-F435】SPI显示屏+LVGL库移植     雅特力在固件库前级目录中,已经有移植好的LVGL库,包含已经写好的DMA2D,用户只需要将打点函数写入即可       然后将这个文件 复制 到工程目录下,在Keil中添加即可,需要注意的是,要开启 C99 模式,不然会编译报错。  具体的添加事宜可以参考 正点原子 的教程: https://www.bilibili.com/video/BV1CG4y157Px/?p=4&spm_id_from=333.880.my_history.page.click        移植过程添加文件较多,这里提供了添加好文件的Keil工程:

  • 2023-07-08
  • 回复了主题帖: 【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显

    秦天qintian0303 发表于 2023-7-8 23:26 这个板子支持几路DAC啊  
    我记得是2个DAC通道输出  

  • 回复了主题帖: 【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显

    Jacktang 发表于 2023-7-8 09:03 RFFT 快速傅里叶逆变换,将幅频曲线逆变换为信号,通过串口调试助手显示还原后的波形,这思路值得学习
    大佬过奖

  • 回复了主题帖: 【雅特力AT-START-F435】ADC采样速率测试5.33MSPS

    lugl4313820 发表于 2023-7-3 08:46 如果对APB1/2 不分频处理,最大采样速率可以达到5.33MSPS 有这样的采样速度,比较牛了吧。
    确实很牛  而且还是12bit采样分辨率,8bit估计可以到10+MSPS

  • 回复了主题帖: 【雅特力AT-START-F435】CRM时钟相关配置,程序运行中更改系统时钟

    秦天qintian0303 发表于 2023-6-14 11:23 我也好想拥有一块雅特力的开发板,不对,我有了,后面我也测试一下

  • 回复了主题帖: 【雅特力AT-START-F435】CRM时钟相关配置,程序运行中更改系统时钟

    damiaa 发表于 2023-6-12 09:16 楼主加油,减少外币依赖,支持国产芯!
    加油!

  • 回复了主题帖: 【雅特力AT-START-F435】基于DSP库实数的FFT和逆FFT变换

    Metazyq 发表于 2023-7-8 15:41 学习学习
    共同进步!

  • 回复了主题帖: 【雅特力AT-START-F435】基于DSP库实数的FFT和逆FFT变换

    Gen_X 发表于 2023-7-7 16:57 我用过:雅特力AT-START-F421,DSP库实数的FFT, 非常好用。
    确实  雅特力这些库都移植好了,用户都不用修改,拿来编译直接用就好

  • 回复了主题帖: 【雅特力AT-START-F435】一种基于AT指令调节PWM占空比

    秦天qintian0303 发表于 2023-7-8 23:19 适合那个示波器看实际引脚输出,串口发命令修改了,然后又发命令出来了,不太直观
    图片最底端 是逻辑分析仪抓取出来的波形,应该大致能体现出来 的确是改变波形占空比了

  • 回复了主题帖: 【雅特力AT-START-F435】SPI显示屏1.77inchTFT测试

    秦天qintian0303 发表于 2023-7-8 23:10 可以搞一个高点分辨率的,240*240用SPI写效果也是不错的  
    手头现在就这一款屏幕了,另一个是陶晶驰的uart串口屏,那个感觉和板卡关系不大,基本都是在电脑上点点图形化操作了

  • 发表了主题帖: 【雅特力AT-START-F435】SPI显示屏1.77inchTFT测试

    【雅特力AT-START-F435】SPI显示屏1.77inchTFT测试           一、SPI初始化     使用 SPI2 ,首先初始化GPIO,使用 PD0 作为软件片选按键,将PD4作为MOIS、PC1作为MISO(没有触摸,未使用到),PD1 作为SCLK的时钟信号线。     每组GPIO都设置为复用功能,强驱动能力,上下拉选择为上拉输出。     初始化GPIO之后最好先将 CS 引脚初始化为高电平 void GPIO_Config(void) { gpio_init_type gpio_initstructure; crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOG_PERIPH_CLOCK, TRUE); /* software cs, pd0 as a general io to control flash cs */ gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_initstructure.gpio_pull = GPIO_PULL_UP; gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT; gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_initstructure.gpio_pins = SPIx_CS; gpio_init(SPIx_CS_Port, &gpio_initstructure); /* sck */ gpio_initstructure.gpio_pull = GPIO_PULL_UP; gpio_initstructure.gpio_mode = GPIO_MODE_MUX; gpio_initstructure.gpio_pins = SPIx_SCK; gpio_init(SPIx_SCK_Port, &gpio_initstructure); gpio_pin_mux_config(SPIx_SCK_Port, GPIO_PINS_SOURCE13, GPIO_MUX_4); /* miso */ gpio_initstructure.gpio_pull = GPIO_PULL_UP; gpio_initstructure.gpio_pins = SPIx_MISO; gpio_init(SPIx_Data_Port, &gpio_initstructure); gpio_pin_mux_config(SPIx_Data_Port, GPIO_PINS_SOURCE0, GPIO_MUX_5); /* mosi */ gpio_initstructure.gpio_pull = GPIO_PULL_UP; gpio_initstructure.gpio_pins = SPIx_MOSI; gpio_init(SPIx_Data_Port, &gpio_initstructure); gpio_pin_mux_config(SPIx_Data_Port, GPIO_PINS_SOURCE1, GPIO_MUX_5); CS_HIGH; }       初始化 SPI2 要将片选选择为软件选择模式,需要注意的是,该TFT屏幕的采样信号为下降沿采样,所以:     配置通道极性为高电平     信号采样点为第二边沿     为了提高刷屏速率,将SPI的分频系数设置为2分频,SYS-Clock运行在72MHz,SPI速率为 72/2/8 = 4.5Mbyte/s。     选择为高位先行模式 void SPIx_Config(void) { spi_init_type spi_init_struct; crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE); spi_default_para_init(&spi_init_struct); spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX; spi_init_struct.master_slave_mode = SPI_MODE_MASTER; spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2; spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB; spi_init_struct.frame_bit_num = SPI_FRAME_8BIT; spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH; spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE; spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; spi_init(SPIx, &spi_init_struct); spi_enable(SPIx, TRUE); }   二、编写通用TFT数据/命令传出接口函数 传输数据: RS 置高 传输命令: RS 拉低   三、初始化LCD屏幕、移植画图函数     移植一下初始化的命令:       移植一下函数接口:     四、主函数中调用     屏幕大小限制为: #define X_MAX_PIXEL 140 #define Y_MAX_PIXEL 170    

  • 发表了主题帖: 【雅特力AT-START-F435】一种基于AT指令调节PWM占空比

    【雅特力AT-START-F435】一种基于AT指令调节PWM占空比 硬件初始化可以参考: 【雅特力AT-START-F435】PWM可调占空比 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn) 【雅特力AT-START-F435】USART实现AT指令方式 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn) 两篇文章。第一篇是基于PWM的占空比调节 第二篇是基于串口实现AT指令的方式。   将两个文件合并,在串口callback函数中编写设置初始化的代码:    可以得到如下的效果    

  • 2023-07-07
  • 发表了主题帖: 【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显

    【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显 前言     本项目为课程设计:DAC+ADC+FFT。DAC使用示波器管观察波形,并连接到本机ADC使用fft还原信号,串口打印信息到电脑上。 DAC和ADC采样都使用定时器触发的方式 DAC只要开始后就不会停止,作为信号源从PA4输出 ADC采样使能 DMA_CH1 通道,当DMA搬移了足够多 (这里设置为了1024) 个采样点之后,停止ADC触发定时器计时,ADC采样结束。 采样完成后,使用 FFT 进行快速傅里叶正变换,得到幅频响应,串口输出幅频响应。 通过 RFFT 快速傅里叶逆变换,将幅频曲线逆变换为信号,通过串口调试助手显示还原后的波形。     一、DAC波形 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); //获取DAC电压波形 GetWave(0); /* 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, DACDUTY-1, (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 = TEST_LENGTH_SAMPLES; dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_base_addr = (uint32_t)dactestInput_q15; dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD; dma_init_struct.memory_inc_enable = TRUE; 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); } 初始化GPIO PA4 为DAC的输出口 使能定时器 TMR2 。设置分频后的频率为1Mhz,然后根据period选择触发Duty 。例如,设置触发Duty为10,那么就是10us触发一次,100kHz触发频率 产生波形函数,产生固定频率的周期波,这里设置为 /* 波形是由直流分量、50Hz 正弦波、25Hz余弦波组成,波形采样率 1024 ,初始相位 0 */ testInput_f32[i] = 1 + 0.5*arm_sin_f32( 2*3.1415926f*50*i/TEST_LENGTH_SAMPLES ) + 1.0*arm_cos_f32( 2*3.1415926f*25*i/1024 ); 波形产出的是 float32_t 的类型,要进行波形放大,并且转化为 12bit 位的数据格式 /* 波形极值,确定放大倍数 */ arm_min_f32(testInput_f32, TEST_LENGTH_SAMPLES, &minData, NULL); arm_max_f32(testInput_f32, TEST_LENGTH_SAMPLES, &maxData, NULL); mulScale = (0x0FFF)*1.0 / (maxData-minData); /* 上移波形,放大 */ for(i=0; i<TEST_LENGTH_SAMPLES; ++i) { dactestInput_q15[i] = ( testInput_f32[i]-minData ) * mulScale; } 使能DMA,开启DAC输出。     二、ADC采样     adc采样可以参考一下这两边文章: 【新提醒】【雅特力AT-START-F435】ADC软触发always、DACTmr2触发、DMA,驱动LED被钳位1.54V问题 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn) 【新提醒】【雅特力AT-START-F435】ADC采样速率测试5.33MSPS - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn) 需要修改的有: 使用 TMR1 触发ADC开始采集,值得注意的是,普通通道只能使用上升沿触发 根据采样定理,采样频率最好大于2倍信号最高频率,即ADCDuty应该最好小于DACDuty   三、FFT转换和RFFT转换     因为采用了按键触发采样的方式,即按下按键的上升沿,开始采样1024个采样点。     所以, 在按键中断服务函数中,开启ADC触发定时器; tmr_counter_enable(TMR1, TRUE);   在ADC的DMA通道全部搬移完成中断中,关闭ADC触发定时器 tmr_counter_enable(TMR1, FALSE); 转换的FFT幅频曲线存放到 testOutputMag_f32 数组中 逆变换的函数图像存放到 testRfft_f32 数组中     四、转换结果查看 使用下面的信号进行DAC输出采样, /* 波形是由直流分量、50Hz 正弦波、25Hz余弦波组成,波形采样率 1024 ,初始相位 0 */ testInput_f32[i] = 1 + 0.5*arm_sin_f32( 2*3.1415926f*50*i/TEST_LENGTH_SAMPLES ) + 1.0*arm_cos_f32( 2*3.1415926f*25*i/1024 ); FFT变换的幅频响应如下:  (图 串口打印的幅频响应频率和幅值百分比)   (图 幅频响应曲线) (图 原信号.下 和 RFFT还原的信号.上)            

  • 发表了主题帖: 【雅特力AT-START-F435】基于Cute的串口示波器

    本帖最后由 zhangbaoyin 于 2023-7-8 12:03 编辑 【雅特力AT-START-F435】基于Cute的串口示波器     为了快速调试和方便的波形显示,发现了一款非常好用的上位机软件 Cute 。    不仅可以自己定义波特率,还可以根据数据点,画出函数图形,入门门槛低,相对于Matlab更容易快速验证单片机代码。   作者开源地址(B站教程): https://www.bilibili.com/video/BV1st4y1G7GB/     产生波形,根据README文件选择通信协议,然后编写代码,每次发送数据 包含帧头、数据帧、帧尾。     基于这样的一段数据包,就可以实现数据->函数图像的转换:   搬运一下 原作者的Gitee和GIthub 软件地址: Github:https://github.com/Bloux-dilicious/serial-lan-debug-software Gitee:https://gitee.com/bloux/serial-lan-debug-software

  • 2023-07-06
  • 回复了主题帖: 【雅特力AT-START-F435】基于DSP库实数的FFT和逆FFT变换

    xinmeng_wit 发表于 2023-7-6 19:53 原始波形是怎么生成的
    是用 直流分量1 + 50次谐波arm_sin(2pi*50*i /1024) + 25次谐波arm_cos_f32(2pi*25*i /1024): testInput_f32 = 1 +     0.5*arm_sin_f32( 2*3.1415926f*50*i/1024 ) +     arm_cos_f32( 2*3.1415926f*25*i/1024 ); 不是用ADC采集到的

  • 发表了主题帖: 【雅特力AT-START-F435】基于DSP库实数的FFT和逆FFT变换

    本帖最后由 zhangbaoyin 于 2023-7-6 17:21 编辑 【雅特力AT-START-F435】基于DSP库实数的FFT和逆FFT变换 一、工程模板更改         找到AT32固件库中的cmsis中的DSP库,路径如下  添加dsp库的文件如下图所示: 只需要添加如图所示的文件就行,其他文件都通过这个c文件包含了 添加头文件 建议开启AC6编译,这样可以节约一些代码空间    测试编译测试一下,如果没有报错就好了     二、FFT     在 TransformFunctions.c 中包含了所有的 FFT ​和 RFFT(reverser fft 逆变换),编译之后展开会有包含的所有函数体的文件(一个函数功能一个c文件) FFT正向变换,主要使用的是 arm_rfft_f32.c 实信号的正向FFT,单精度浮点32bit的运算。打开该文件,在代码 ​​​​564 有该函数的描述: 可以发现,要使用正向FFT变换,需要下调用一个前向函数 arm_rfft_fast_init_f32() 初始化,该函数也有一个单独的c文件存放,直接调用就好。 参数 S :是一个结构体,从初始化结构体中产出。 参数 p :是一个指向源数据的数组 参数 pOut :是一个指向结果数据的数组 参数 ifftFlag :为 0 表示正变换,为 1 表示逆变换。数据流动方向都是从 p -> pOut    在主函数中调用如下: arm_rfft_fast_init_f32(&S, 1024); /* 1024 点实序列快速 FFT */ arm_rfft_fast_f32(&S, testInput_f32, testOutput_f32, ifftFlag);   三、FFT -> 幅频响应     FFT变换之后,不论是实信号还是复信号,结构都会变成一个复数,a + bi     在结果存放中,以两个数据位组合成一个组合,第一个位置存放的是实部 a ,第二个位置存放的是虚部 b     欲求得幅频响应,对每一个数据组取模,(a^2 + b^2) ^ (1/2) 就能得到该频率下的幅值     对于复数的模,也有加速的函数 arm_cmplx_mag_f32();  调用方式如下: /* 这里求解了 1024 组模值,实际函数 arm_rfft_fast_f32只求解出了 512 组 */ arm_cmplx_mag_f32(testOutput_f32, testOutputMag_f32, TEST_LENGTH_SAMPLES);   四、FFT逆变换 在 (二、FFT) 中可以知道,只需要将u8位 ifftFlag 置1就可求得FFT逆变换 /* 1024 点实序列快速逆 FFT */ ifftFlag = 1; arm_rfft_fast_f32(&S, testOutput_f32, testRfft_f32, ifftFlag);     五、实验效果 使能按键中断,按键按下后,切换波形输出(原始波形、FFT变换->FFT逆变换之后的波形) 对比两个波形,如果一直,则FFT验证通过 LED3亮、LED4灭,为原始波形 LED3灭、LED4亮,为转换波形 [localvideo]66a7b1def960431dbed0ad7d1e34c73c[/localvideo]     占用资源大小如下: Code (inc. data) RO Data RW Data ZI Data Debug 12524 352 81680 40 53344 278227 Grand Totals 12524 352 81680 40 53344 278227 ELF Image Totals 12524 352 81680 40 0 0 ROM Totals ============================================================================== Total RO Size (Code + RO Data) 94204 ( 92.00kB) Total RW Size (RW Data + ZI Data) 53384 ( 52.13kB) Total ROM Size (Code + RO Data + RW Data) 94244 ( 92.04kB) ==============================================================================          

  • 2023-07-03
  • 发表了主题帖: 【雅特力AT-START-F435】USART实现AT指令方式

    【雅特力AT-START-F435】USART实现AT指令方式 首先看效果: 使用usart1,开启串口接收中断。 每次接收中断一个字符,保存到接收缓冲区 uint8_t usart1_rec_data_buff[128]; 结束标志为字符 '\n'    实现步骤: 一、判断中断类型     在中断服务函数中,判断是否为接收中断标志:      如果usart1的状态寄存器(sts)的rdbf(receive data buffer full,接收数据寄存器满),则跳转到回调函数 USART1_CallBack() 完成判断操作。   二、读接收寄存器     *(usart1_rec_data_buff+buff_index) = USART1->dt;     读取接收寄存器后,自动清除接收中断标志位。    二、判断是否为有效AT指令     第一层 if( *(usart1_rec_data_buff+buff_index) == '\n' )  判断是否接收完成 (‘\n’结尾)。如果接收指令完成,进入第二次判断     第二层 指令 if(  strstr( (const char*)usart1_rec_data_buff, "AT+SD" ) != NULL  ) 判断AT指令的类型,在循环体里进行相应操作 /* 输入的命令为AT+SD */ if( strstr( (const char*)usart1_rec_data_buff, "AT+SD" ) != NULL ) { ... } /* 输入的命令为AT+SPD */ else if( strstr( (const char*)usart1_rec_data_buff, "AT+SPD" ) != NULL ) { ... } /* 错误输入 */ else { ... }    三、跳过AT指令,读取AT后的数据 首先使用while循环,跳转到数据位的索引值 index 再从 usart1_rec_data_buff+index  指针的位置开始格式化数据到变量中,使用的是 sscanf 函数,具体的函数操作见下: https://www.runoob.com/cprogramming/c-function-sscanf.html     如果需要增加其他AT指令,在回调函数的第二层循环中,添加  else if( strstr( (const char*)usart1_rec_data_buff, "AT+xxx" ) != NULL ) "AT+xxx" 就是指令的开头形式  ,AT后的数据参数在 if 判断里筛选就好      

  • 2023-06-30
  • 发表了主题帖: 【雅特力AT-START-F435】PWM可调占空比

    【雅特力AT-START-F435】PWM可调占空比 一、时钟配置     所有定时器连接到APB2总线上,在 system_clock_config 函数中对APB2二分频,所以在计算TMR1时钟周期的时候需要x2操作。     设置PWM的频率为:timerperiod = ((crm_clocks_freq_struct.apb2_freq * 2) / 10000 ) - 1;     计算TMR1的分频系数,设置为不分频。     计算PWM占空比: /* tmr1 configuration --------------------------------------------------- generate 7 pwm signals with 4 different duty cycles: prescaler = 0, tmr1 counter clock = apb2_freq *2 the objective is to generate 7 pwm signal at 17.57 khz: - tim1_period = (apb2_freq * 2 / 17570) - 1 the channel 1 and channel 1n duty cycle is set to 50% the channel 2 and channel 2n duty cycle is set to 37.5% the channel 3 and channel 3n duty cycle is set to 25% the channel 4 duty cycle is set to 12.5% the timer pulse is calculated as follows: - channelxpulse = dutycycle * (tim1_period - 1) / 100 ----------------------------------------------------------------------- */   二、PWM输出配置     设置为PWMB模式、使能输出、不使能互补输出、极性选择LOW、空闲状态为高电位。     设置占空比函数为 tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_1, channel1pulse); /* channel 1 configuration in output mode */ tmr_output_default_para_init(&tmr_output_struct); tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B; tmr_output_struct.oc_output_state = TRUE; tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW; tmr_output_struct.oc_idle_state = TRUE; tmr_output_struct.occ_output_state = TRUE; tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_HIGH; tmr_output_struct.occ_idle_state = FALSE; /* channel 1 */ tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_1, &tmr_output_struct); tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_1, channel1pulse); 在主函数中,while循环中更改占空比: PWM周期为100us,每100us增加1%占空比,如下   二、PWM信号抓取 抓取的波形如下  在临界点发生突变的波形如下  

  • 2023-06-26
  • 发表了主题帖: 【雅特力AT-START-F435】ADC采样速率测试5.33MSPS

    本帖最后由 zhangbaoyin 于 2023-6-26 20:27 编辑 【雅特力AT-START-F435】ADC采样速率测试5.33MSPS 一、时钟配置 从时钟树上可以看到: ADC通道的最大时钟速率为80MHz。 ADC全部挂载到APB2总线上,配置系统时钟使用apb2 不分频 总体的系统时钟配置为 Sys-Clock 320MHz APB1 320MHz APB2 320MHz ADC-Freq 80MHz     二、代码设计 将ADC设置为:软件触发+连续转换+2.5采样周期 使用基本定时器TMR6定时1秒,每次溢出产生中断TMR_OVF_INT ADC转换完成后产生转换完成中断ADC_OCCE_INT 在ADC转换完成中断内 将计数值++,这个计数值就是ADC的转换频率 /** * [url=home.php?mod=space&uid=159083]@brief[/url] this function handles adc1_2_3 handler. * @param none * @retval none */ void ADC1_2_3_IRQHandler(void) { if(adc_flag_get(ADC1, ADC_OCCE_FLAG) != RESET) { adc_flag_clear(ADC1, ADC_OCCE_FLAG); adc1_conversion_end_flag++; } } void TMR6_DAC_GLOBAL_IRQHandler(void) { if(tmr_flag_get(TMR6, TMR_OVF_FLAG) != RESET) { printf("ADC_Value: %u\tFreq: %dHz\n", ADC1->odt, adc1_conversion_end_flag); adc1_conversion_end_flag = 0; tmr_flag_clear(TMR6, TMR_OVF_FLAG); } }   三、实验结果: 如果对APB1/2 二分频处理,最大采样速率只有4.92MSPS  如果对APB1/2 不分频处理,最大采样速率可以达到5.33MSPS    

  • 2023-06-19
  • 发表了主题帖: 【雅特力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。 使用DMA1-CH1,开启DMA1-CH1的NVIC中断(DMA1_Channel1_IRQn),用于记录DMA搬移成功的次数,也就是计算采样率(具体计算采样率的代码在下一节) buffer_size:DMA的一次搬移数据个数,就一个ADC通道,采用一个数据就好 direction:由ADC到内存,为DMA_DIR_PERIPHERAL_TO_MEMORY(外设到内存) memory_base_addr为内存地址,设置为一个数组就好,然后传入数组首地址,并将地址转化为 (uint32_t) 类型,而不是 (* uint32_t) 的指针类型 因为使用的是12bitADC采样,所以DMA传输宽度使用WIDTH_HALFWORD(16bit半字宽度) 外设和内存自动地址增加设置为FALSE 将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 ADC模式设置为独立模式 ADC_INDEPENDENT_MODE ADC挂载到HCLK(和CPU同频率),为了使ADC采样速度最大,采用2分频 ADC_HCLK_DIV_2  common_dma_mode不用配置,在独立模式不起作用 ADC sequence_mode设置为FALSE,不使用序列模式(因为就使用了一个ADC通道) ADC repeat_mode设置为TRUE,重复模式,就触发一次,然后一直采样 ADC data_align 对齐模式选择为右对齐 ADC ordinary_channel_length 通道个数选择为1个 配置这个通道的采样顺序,采样时间为92.5个ADC时钟周期 选择数据寄存器的对齐模式为右对齐 使能ADC 使能ADC的DMA请求 开启ADC 开启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 设置为模拟模式 因为要驱动外设,所以驱动能力选择为强驱动模式GPIO_DRIVE_STRENGTH_STRONGER 选择TMR2作为触发源,触发频率为1kHz 设置为向上计数模式 设置计数上限为999(从0开始计数到999经历1000个时钟周期) TMR2的时钟频率设置为:(systemclock/(systemclock/1000000))/1000 = 1KHz  模式选择为 TMR_PRIMARY_SEL_OVERFLOW:tmr primary mode select overflow 配置DAC1   DAC1触发选择TMR2 DAC_TMR2_TRGOUT_EVENT 使能DAC2触发模式 不启用噪声波 使能输出增益( dac_output_buffer_enable(DAC1_SELECT, TRUE) ),这个是必须的,不然LED无法驱动 使能DAC(开启DAC) 配置DMA 选择DMA通道为DMA1-CH2 buffer_size:DMA的一次搬移数据个数,就一个DAC通道,采用一个数据就好 direction:由ADC到内存,为DMA_DIR_MEMORY_TO_PERIPHERAL(内存到外设) memory_base_addr为内存地址,设置为一个数组就好,然后传入数组首地址,并将地址转化为 (uint32_t) 类型,而不是 (* uint32_t) 的指针类型 peripheral_base_addr为外设地址:(DAC_BASE+0x008) // DAC1的12位右对齐数据保持寄存器(DAC_D1DTH12R),偏移地址008H 因为使用的是12bitADC采样,所以DMA传输宽度使用WIDTH_HALFWORD(16bit半字宽度) 外设和内存自动地址增加设置为FALSE 将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); }     三、实验效果     [localvideo]cf4692fc8cadf88ae9f77cab2ae3c900[/localvideo] 如果不开启输出增益D1OBDIS使能,DAC的GPIO驱动能力比LED端口的驱动能力弱,无法抵抗LED的稳压特性,最低电压被钳位在稳压的1.54v。 所以如果要驱动外设,一点要开启输出增益。

学过的课程

最近访客

< 1/2 >

统计信息

已有16人来访过

  • 芯积分:150
  • 好友:--
  • 主题:13
  • 回复:12
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言