bigbat

  • 2025-01-27
  • 回复了主题帖: 在越南出差时登陆不了

    okhxyyo 发表于 2025-1-27 11:17 原来出差去了呀!新年快乐呀! 我遇到过这种故障,做网站一定要使用带时区的时间值。

  • 2025-01-24
  • 回复了主题帖: 【FRDM-MCXN947测评】CAN FD通讯测试

    freebsder 发表于 2025-1-24 17:59 can用起来还是各种麻烦,我们现在没必要的地方用以太网,很多复杂的事就完全没事了。 我的感觉和你一样,以太网似乎更方便。CAN 可能是不了解的缘故,感觉很复杂

  • 发表了主题帖: 【FRDM-MCXN947测评】相移PWM输出测试

    本帖最后由 bigbat 于 2025-1-24 16:02 编辑 1、测试介绍 MCXN947系列MCU的FlexPWM 模块,可以通过独立的时钟控制两个通道输出:具有可控制相位输出的PWM波形。每个通道A相或B相可以独立的任意调节PWM相位。该功能可以实现: 中心对齐PWM:     边缘对齐PWM:      相移PWM:   双开关 PWM:   其中的相移输出是我工作中需要的输出,旧有的设计需要多个计数器相互配合实现复杂,而且输出精度和实时性较差,不能实现较为精准的输出和控制。我的要求是:两个通道,A先开启进行预充电,然后在开启输出功率管工作。原有的设计经常出现中断的现象。就是由于相位控制不精确造成的。所以该功能正是我需要的。本次测试也是对该功能进行测试。 硬件: FRDM-MCXN947开发板一块 双通道100M示波器一台 USB TYPE-C电缆 软件: GCC ARM Embedded 13.2.1编译器。 测试实现的效果如:   PWM_A相:输出 PWM_B相:输出 2、设置及程序分析 该测试程序参考MCXN947的SDK PWM程序。  NXP的配置工具MCUXpresso Config Tools v16.1除了可以配置芯片引脚路由外,其它的我到现在都没有发现其它的更详细的配置项目。 第一段: 程序的思路是通过MCU PWM的两个寄存器来控制PWM的脉宽位置。参考下面的初始化代码。 /******************************************************************************* * Code ******************************************************************************/ static void PWM_DRV_Init3PhPwm(void) { uint16_t deadTimeVal; pwm_signal_param_t pwmSignal[2]; uint32_t pwmSourceClockInHz; uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCY; pwmSourceClockInHz = PWM_SRC_CLK_FREQ; /* Set deadtime count, we set this to about 650ns */ deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000; pwmSignal[0].pwmChannel = kPWM_PwmA; pwmSignal[0].level = kPWM_HighTrue; pwmSignal[0].dutyCyclePercent = 50; /* 1 percent dutycycle */ pwmSignal[0].deadtimeValue = deadTimeVal; pwmSignal[0].faultState = kPWM_PwmFaultState0; pwmSignal[0].pwmchannelenable = true; pwmSignal[1].pwmChannel = kPWM_PwmB; pwmSignal[1].level = kPWM_HighTrue; /* Dutycycle field of PWM B does not matter as we are running in PWM A complementary mode */ pwmSignal[1].dutyCyclePercent = 50; pwmSignal[1].deadtimeValue = deadTimeVal; pwmSignal[1].faultState = kPWM_PwmFaultState0; pwmSignal[1].pwmchannelenable = true; /*********** PWMA_SM0 - phase A, configuration, setup 2 channel as an example ************/ PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, pwmSignal, 2, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); /*********** PWMA_SM1 - phase B configuration, setup PWM A channel only ************/ #ifdef DEMO_PWM_CLOCK_DEVIDER PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_1, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz / (1 << DEMO_PWM_CLOCK_DEVIDER)); #else PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_1, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); #endif /*********** PWMA_SM2 - phase C configuration, setup PWM A channel only ************/ #ifdef DEMO_PWM_CLOCK_DEVIDER PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_2, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz / (1 << DEMO_PWM_CLOCK_DEVIDER)); #else PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_2, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); #endif } 整个参数配置为 一个结构体 pwm_signal_param_t pwmSignal[2]; 一个配置函数PWM_SetupPwm(); 函数设计有点过于抽象,函数的设计思路是按照工程化的思维模式设计的,例如:占空比(pwmSignal[0].dutyCyclePercent = 50;)、相位角(pwmSignal[0].deadtimeValue    = deadTimeVal;)等概念来输入。对于我这种嵌入式程序思维的人来说,总是觉得不够直接(好像没有掌控感,呵呵!好像NXP不能够让我装了,有点不爽呃) 第二段: 这个思路主要是控制PWM的输出。参考下面代码 /*! * [url=home.php?mod=space&uid=159083]@brief[/url] Main function */ int main(void) { /* Structure of initialize PWM */ pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; uint32_t pwmVal = 4; /* Board pin, clock, debug console init */ /* attach FRO 12M to FLEXCOMM4 (debug console) */ CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u); CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); BOARD_InitPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Enable PWM1 SUB Clockn */ SYSCON->PWM1SUBCTL |= (SYSCON_PWM1SUBCTL_CLK0_EN_MASK | SYSCON_PWM1SUBCTL_CLK1_EN_MASK | SYSCON_PWM1SUBCTL_CLK2_EN_MASK); PRINTF("FlexPWM driver example\n"); /* * pwmConfig.enableDebugMode = false; * pwmConfig.enableWait = false; * pwmConfig.reloadSelect = kPWM_LocalReload; * pwmConfig.clockSource = kPWM_BusClock; * pwmConfig.prescale = kPWM_Prescale_Divide_1; * pwmConfig.initializationControl = kPWM_Initialize_LocalSync; * pwmConfig.forceTrigger = kPWM_Force_Local; * pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; * pwmConfig.reloadLogic = kPWM_ReloadImmediate; * pwmConfig.pairOperation = kPWM_Independent; */ PWM_GetDefaultConfig(&pwmConfig); #ifdef DEMO_PWM_CLOCK_DEVIDER pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER; #endif /* Use full cycle reload */ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; /* PWM A & PWM B form a complementary PWM pair */ pwmConfig.pairOperation = kPWM_ComplementaryPwmA; pwmConfig.enableDebugMode = true; /* Initialize submodule 0 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) == kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* Initialize submodule 1, make it use same counter clock as submodule 0. */ pwmConfig.clockSource = kPWM_Submodule0Clock; pwmConfig.prescale = kPWM_Prescale_Divide_1; pwmConfig.initializationControl = kPWM_Initialize_MasterSync; if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_1, &pwmConfig) == kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* Initialize submodule 2 the same way as submodule 1 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_2, &pwmConfig) == kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* * config->faultClearingMode = kPWM_Automatic; * config->faultLevel = false; * config->enableCombinationalPath = true; * config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig); #ifdef DEMO_PWM_FAULT_LEVEL faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL; #endif /* Sets up the PWM fault protection */ PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_0, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_1, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_2, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_3, &faultConfig); /* Set PWM fault disable mapping for submodule 0/1/2 */ PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); /* Call the init function with demo configuration */ PWM_DRV_Init3PhPwm(); /* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true); /* Start the PWM generation from Submodules 0, 1 and 2 */ PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2); while (1U) { /* Delay at least 100 PWM periods. */ SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCY) * 100, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); pwmVal = pwmVal + 4; /* Reset the duty cycle percentage */ if (pwmVal > 100) { pwmVal = 4; } /* Update duty cycles for all 3 PWM signals */ PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_SignedCenterAligned, pwmVal); PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_SignedCenterAligned, (pwmVal >> 1)); PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_SignedCenterAligned, (pwmVal >> 2)); /* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true); } 主要代码是: (1)初始化模块(submodule 0/1/2) /* Set PWM fault disable mapping for submodule 0/1/2 */ PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); (2)开始定时器 PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2); (3)程序循环中控制PWM脉冲的量值 /* Update duty cycles for all 3 PWM signals */ PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_SignedCenterAligned, pwmVal); PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_SignedCenterAligned, (pwmVal >> 1)); PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_SignedCenterAligned, (pwmVal >> 2));   3、测试过程 (1) 将A0相输出和A1输出连接到示波器上去。 (2)将USB  Type-C电缆连接到PC主机 (3)运行程序  调节示波器,可以查看输出波形。   波形输出为设计的方式,但是波形出现了很多的“过冲”现象,不知道是什么原因造成的。 4、总结 通过测试可以更加深入的了解NXP FlexPWM的控制原理,NXP使用较为工程化的函数封装来简化编程的复杂度。我个人觉得如果想很好的了解FlexPWM的模块工作原理还是需要了解各种寄存器和模块的设计原理。    

  • 2025-01-23
  • 发表了主题帖: 【MCXN947开发板测评】I2C总线设备的兼容性测试

    1、测试简介 测试如何使用 CMSIS i2c 驱动作为主机,通过I2C总线控制SSD1306 OLED显示图像。通过轮询方式进行I2C控制通讯。 硬件要求: Type-C USB 线 FRDM - MCXN947 开发板 SSD1306 OLED屏 个人计算机 软件: GCC ARM 嵌入式 13.2.1 Putty串口终端 2、设置与程序 OLED屏需按以下方式连接: 主机(LPI2C2)    连接    SSD1306 开发板                   OLED  SCL     J2 引脚 20   <----------> SCL    SDA     J2 引脚 18   <----------> SDA  GND    J3 引脚 14  <----------> GND P3.3V  J3 引脚 4  <----------> 3.3V /* * Copyright 2017 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Standard C Included Files */ #include <stdio.h> #include <string.h> #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_lpi2c.h" #include "fsl_SSD1306_I2C.h" /******************************************************************************* * Definitions ******************************************************************************/ //#define EXAMPLE_I2C_MASTER_BASE (LPI2C2_BASE) #define LPI2C_MASTER_CLOCK_FREQUENCY CLOCK_GetLPFlexCommClkFreq(2u) #define WAIT_TIME 10U //#define EXAMPLE_I2C_MASTER ((LPI2C_Type *)EXAMPLE_I2C_MASTER_BASE) #define LPI2C_MASTER_SLAVE_ADDR_7BIT 0x3CU #define LPI2C_BAUDRATE 100000U #define LPI2C_DATA_LENGTH 33U /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ uint8_t g_master_txBuff[LPI2C_DATA_LENGTH]; uint8_t g_master_rxBuff[LPI2C_DATA_LENGTH]; /******************************************************************************* * Code ******************************************************************************/ /*! * [url=home.php?mod=space&uid=159083]@brief[/url] Main function */ int main(void) { lpi2c_master_config_t masterConfig; //status_t reVal = kStatus_Fail; //uint8_t deviceAddress = 0x01U; size_t txCount = 0xFFU; /* attach FRO 12M to FLEXCOMM4 (debug console) */ CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u); CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); /* attach FRO 12M to FLEXCOMM2 */ CLOCK_SetClkDiv(kCLOCK_DivFlexcom2Clk, 1u); CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); PRINTF("\r\nLPI2C board2board polling example -- Master transfer.\r\n"); LPI2C_MasterGetDefaultConfig(&masterConfig); /* Change the default baudrate configuration */ masterConfig.baudRate_Hz = LPI2C_BAUDRATE; /* Initialize the LPI2C master peripheral */ LPI2C_MasterInit(EXAMPLE_I2C_MASTER, &masterConfig, LPI2C_MASTER_CLOCK_FREQUENCY); /* Initialize the SSD1306 display*/ OLED_Init(); OLED_Refresh(); OLED_Clear(); /*Print welcome message*/ OLED_Copy_Image(&logo_nxp[0], sizeof(logo_nxp)); OLED_Refresh(); OLED_Set_Text(10, 52, kOLED_Pixel_Set, "MCXN947 I2C", 2); OLED_Refresh(); PRINTF("\r\nEnd of LPI2C example .\r\n"); while (1) { } } OLED SSD1306驱动程序fsl_SSD1306_I2C.c /*----esta modificada para usar el I2C1, en caso de utilizar otro cambiar todo * lo que diga I2C1 por la base del I2C usado--- */ /*---- BASADO EN fsl_SSD1306.h para SPI de NXP ------*/ #include "fsl_gpio.h" #include "fsl_lpi2c.h" #include <fsl_SSD1306_I2C.h> // #include "fsl_Systick_Delay.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /*! @brief OLED buffer */ static uint8_t OLED_Buffer[(OLED_WIDTH * OLED_HEIGHT) / 8]; /******************************************************************************* * Code ******************************************************************************/ static void OLED_Command(uint8_t Cmd) { lpi2c_master_transfer_t xfer = {0}; xfer.data = (uint8_t *)&Cmd; xfer.dataSize = sizeof(Cmd); xfer.flags = kLPI2C_TransferDefaultFlag; xfer.slaveAddress = SSD1306_ADDRESS_1; xfer.direction = kLPI2C_Write; xfer.subaddress = 0x0; xfer.subaddressSize = 1; LPI2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER, &xfer); } static void OLED_Data(uint8_t *Data) { lpi2c_master_transfer_t xfer = {0}; /*Start Transfer*/ xfer.data = Data; xfer.dataSize = sizeof(OLED_Buffer); xfer.flags = kLPI2C_TransferDefaultFlag; xfer.slaveAddress = SSD1306_ADDRESS_1; xfer.direction = kLPI2C_Write; xfer.subaddress = 0x40; xfer.subaddressSize = 1; LPI2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER, &xfer); } static void OLED_Reset(void) { OLED_Command(OLED_DISPLAYON); // for(int i=0; i<5000; i++); //delay //1ms // SysTick_Delay_ms(1); OLED_Command(OLED_DISPLAYOFF); // for(int i=0; i<5000; i++); //delay //1ms // SysTick_Delay_ms(1); OLED_Command(OLED_DISPLAYON); // for(int i=0; i<50000; i++); //delay //10ms // SysTick_Delay_ms(10); } static void OLED_Config_Display(void) { OLED_Reset(); // Turn the OLED Display off OLED_Command(OLED_DISPLAYOFF); // Configure the display for 128x64 pixels, KS0108 mode OLED_Command(OLED_SETDISPLAYCLOCKDIV); OLED_Command(0x80); OLED_Command(OLED_SETMULTIPLEX); OLED_Command(OLED_HEIGHT - 1); // LCD Height OLED_Command(OLED_SETDISPLAYOFFSET); OLED_Command(0x0); OLED_Command(OLED_SETSTARTLINE | 0x0); OLED_Command(OLED_CHARGEPUMP); OLED_Command(0x14); // Use 3.3V supply to generate high voltage supply OLED_Command(OLED_MEMORYMODE); OLED_Command(0x00); OLED_Command(OLED_SEGREMAP | 0x1); OLED_Command(OLED_COMSCANDEC); OLED_Command(OLED_SETCOMPINS); OLED_Command(0x12); OLED_Command(OLED_SETCONTRAST); OLED_Command(0xCF); OLED_Command(OLED_SETPRECHARGE); OLED_Command(0xF1); OLED_Command(OLED_SETVCOMDETECT); OLED_Command(0x40); OLED_Command(OLED_DISPLAYALLON_RESUME); OLED_Command(OLED_NORMALDISPLAY); OLED_Command(OLED_DEACTIVATE_SCROLL); OLED_Command(OLED_COLUMNADDR); OLED_Command(0); OLED_Command(OLED_WIDTH - 1); OLED_Command(OLED_PAGEADDR); OLED_Command(0); OLED_Command(OLED_HEIGHT / 8 - 1); // Turn the OLED display on! OLED_Command(OLED_DISPLAYON); OLED_Command(OLED_SETLOWCOLUMN | 0x0); // low col = 0 OLED_Command(OLED_SETHIGHCOLUMN | 0x0); // hi col = 0 OLED_Command(OLED_SETSTARTLINE | 0x0); // line #0 } static int OLED_Render_Char(uint8_t X_axis, uint8_t Y_axis, uint8_t SC, int8_t String, uint8_t Scale) { uint8_t px, py; uint16_t start_pos; if ((X_axis >= OLED_WIDTH) || (Y_axis >= OLED_HEIGHT)) { return 1; } if (String > 127) { return 2; } if (Scale > 3) { return 3; } start_pos = ((uint8_t)String) * 7; // Characters have a 7 row offset for (px = 0; px < 5; px++) { for (py = 0; py < 7; py++) { if ((font5x7[start_pos + py] >> (7 - px)) & 1) { switch (Scale) { case 3: OLED_Set_Pixel(X_axis + (px * Scale), Y_axis + (py * Scale), SC); OLED_Set_Pixel(X_axis + (px * Scale) + 1, Y_axis + (py * Scale), SC); OLED_Set_Pixel(X_axis + (px * Scale) + 2, Y_axis + (py * Scale), SC); OLED_Set_Pixel(X_axis + (px * Scale), Y_axis + (py * Scale) + 1, SC); OLED_Set_Pixel(X_axis + (px * Scale) + 1, Y_axis + (py * Scale) + 1, SC); OLED_Set_Pixel(X_axis + (px * Scale) + 2, Y_axis + (py * Scale) + 1, SC); OLED_Set_Pixel(X_axis + (px * Scale), Y_axis + (py * Scale) + 2, SC); OLED_Set_Pixel(X_axis + (px * Scale) + 1, Y_axis + (py * Scale) + 2, SC); OLED_Set_Pixel(X_axis + (px * Scale) + 2, Y_axis + (py * Scale) + 2, SC); break; case 2: OLED_Set_Pixel(X_axis + (px * Scale), Y_axis + (py * Scale), SC); OLED_Set_Pixel(X_axis + (px * Scale) + 1, Y_axis + (py * Scale), SC); OLED_Set_Pixel(X_axis + (px * Scale), Y_axis + (py * Scale) + 1, SC); OLED_Set_Pixel(X_axis + (px * Scale) + 1, Y_axis + (py * Scale) + 1, SC); break; case 1: default: OLED_Set_Pixel(X_axis + px, Y_axis + py, SC); break; } } } } return 0; } void OLED_Init(void) { /*Give the display a reset*/ OLED_Reset(); /* Clear the framebuffer*/ OLED_Clear(); /*Configure the OLED display controller*/ OLED_Config_Display(); } void OLED_Refresh(void) { OLED_Command(0xb0); OLED_Command(((0 & 0xf0) >> 4) | 0x10); OLED_Command((0 & 0x0f) | 0x01); OLED_Data(&OLED_Buffer[0]); } void OLED_Clear(void) { memset(OLED_Buffer, 0, sizeof(OLED_Buffer)); } void OLED_Fill(uint8_t Pattern) { memset(OLED_Buffer, Pattern, sizeof(OLED_Buffer)); } void OLED_Display_Mode(uint8_t Mode) { if (Mode) { OLED_Command(OLED_INVERTDISPLAY); } else { OLED_Command(OLED_NORMALDISPLAY); } } void OLED_Set_Pixel(uint8_t X_axis, uint8_t Y_axis, uint8_t SC) { if ((X_axis >= OLED_WIDTH) || (Y_axis >= OLED_HEIGHT)) { // Do nothing } else { switch (SC) { case kOLED_Pixel_Clear: OLED_Buffer[X_axis + (Y_axis / 8) * OLED_WIDTH] &= ~(1 << (Y_axis & 7)); break; case kOLED_Pixel_Set: OLED_Buffer[X_axis + (Y_axis / 8) * OLED_WIDTH] |= (1 << (Y_axis & 7)); break; } } } void OLED_Set_Text(uint8_t X_axis, uint8_t Y_axis, uint8_t SC, char *String, uint8_t Scale) { uint16_t Cont; uint16_t xscaled; if ((X_axis >= OLED_WIDTH) || (Y_axis >= OLED_HEIGHT)) { // Do nothing } else { if (Scale > 3) { // Do nothing } else { for (Cont = 0; String[Cont] != '\0'; Cont++) { // Catch overflow when scaling! xscaled = X_axis + (Cont * 5 * Scale); if (xscaled > OLED_WIDTH) { // Do nothing } else { OLED_Render_Char(xscaled, Y_axis, SC, String[Cont], Scale); } } } } } void OLED_Copy_Image(const uint8_t *Img, uint16_t size) { uint16_t CpyBuffer; OLED_Clear(); for (CpyBuffer = 0; CpyBuffer < size - 1; CpyBuffer++) { OLED_Buffer[CpyBuffer] = *(Img + CpyBuffer); } }   3、测试过程 将开发板与OLED相连接     4、总结 MCXN的I2C编程使用查询模式对MCU不断查询。所以对于MCU有一定的压力,对于双核的系统可以发挥效能。  

  • 回复了主题帖: 【FRDM-MCXN947测评】CAN FD通讯测试

    freebsder 发表于 2025-1-23 16:35 有开源的CANFD的canopen协议栈吗? 是的,我之前了解过该项目,但是项目的资料不是很多,而且这类项目也不多。远不如以太网

  • 发表了主题帖: 【FRDM-MCXN947测评】使用NPU对象检测测试

    1、测试介绍 测试是基于 TensorFlow Lite 模型的“对象检测器”实现对象检测测试。 此测试是使用eQI工具经过调整后的TensorFlow Lite模型,转换后的模型可在带有NPU的MCXN MCU 上运行。 程序将三通道彩色图像转化为量化 Mobilenet 的卷积神经网络模型输入,该输入通过“对象检测器模型”在NPU运算后输出为1000种图像分类之一。 程序静态图像为输入。NPU运算结果通过UART进行输出。 待识别的图像为:   该图像需要预先转换为C语言的数组文件image_data.h,该文件代替摄像头输入。 硬件: FRDM-MCXN947开发板一块 USB  Type-C电缆一条 软件: GCC ARM Embedded 13.2.1编译器 PUTTY 串口终端软件 eIQ_Toolkit 模型工具软件 2、模型转换 测试的模型可以从http://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_0.25_128.tgz处下载。 输入文件 https://commons.wikimedia.org/wiki/File:Stopwatch2.jpg (1)将Stopwatch2.jpg文件使用python脚本转成OpenCV格式数组 import cv2 import numpy as np img = cv2.imread('test/Stopwatch2.jpg') img = cv2.resize(img,(128,128)) img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) with open('image_data.h','w') as fout: print('#define STATIC_IMAGE_NAME "stopwatch"',file=fout) print('static const uint8_t image_data[] = {',file=fout) img.tofile(fout,', ','0x%02X') print('};\n',file=fout) (2)使用eIQ_Toolkit软件将TensorFlow Lite 模型模型转换成MCXN947 NPU能够使用的int8结构模型   使用MODEL TOOL将模型转换成MCXN NPU格式  模型的层次信息  使用软件左上角Covert功能转换格式     目标文件custom_model_converted.tflite     转后的文件格式为int8格式,该格式可以运行在MCXN NPU上面。 3、模型引入 将custom_model_converted.tflite文件放入model_data.h格式当中。   整个文件成为uint8_t  model_data[]数组。 总结一下就是将eIQ转换的模型放到一个C语言数组当中。这是我看了好几遍文档才明白过来的。 4、项目介绍 使用MCUXpresso Config Tools 引入项目   整个程序主要为两部分 一、对使用的模型进行初始化; 二、将输入数据转换成NPU数组; int main(void) { BOARD_Init(); TIMER_Init(); DEMO_PrintInfo(); if (MODEL_Init() != kStatus_Success) { PRINTF("Failed initializing model" EOL); for (;;) {} } tensor_dims_t inputDims; tensor_type_t inputType; uint8_t* inputData = MODEL_GetInputTensorData(&inputDims, &inputType); tensor_dims_t outputDims; tensor_type_t outputType; uint8_t* outputData = MODEL_GetOutputTensorData(&outputDims, &outputType); while (1) { /* Expected tensor dimensions: [batches, height, width, channels] */ if (IMAGE_GetImage(inputData, inputDims.data[2], inputDims.data[1], inputDims.data[3]) != kStatus_Success) { PRINTF("Failed retrieving input image" EOL); for (;;) {} } MODEL_ConvertInput(inputData, &inputDims, inputType); auto startTime = TIMER_GetTimeInUS(); MODEL_RunInference(); auto endTime = TIMER_GetTimeInUS(); MODEL_ProcessOutput(outputData, &outputDims, outputType, endTime - startTime); } }   5、测试过程 使用USB type-c连接开发板和PC   打开Putty终端   测试结果:  秒表 stopwatch 置信度:(86%) 6、总结 该测试是为了测评进行的,我之前尝试了好多次的摄像头实时取数的程序,但是摄像头的调试关于复杂,而且我没有显示屏也不能实时看到结果。但是整个NPU项目的流程已经搞清楚了。 非常期待手头阔绰的网友能够给出更加精彩的测评。  

  • 发表了主题帖: 【FRDM-MCXN947测评】CAN FD通讯测试

    本帖最后由 bigbat 于 2025-1-23 11:40 编辑 1、测试介绍 MCXN947VDF MCU具有CAN FD外设。本次测试CAN 通讯测试。测试需要两块具有CAN FD通讯的设备。我这里使用一块FRM-MCXA156开发板作为从机进行通讯。两块开发板通过 CAN 总线连接。当用户在终端输入要发送的 CAN 消息数量时,端点 A(开发板 A)会向端点 B(开发板 B)发送 CAN/CANFD 消息。端点 B 使用两个接收队列轮流接收消息,并且在任意一个队列满时,将消息内容和接收队列编号打印到终端。 测试硬件: FRDM-MCXN947 开发板一块 FRDM-MCXA156 开发板 一块 PC计算机一台 USB type-c电缆线两条 杜邦连接一组 软件: GCC ARM Embedded 13.2.1编译器 PUTTY串口终端   2、测试配置与程序 将引脚引脚·P1_10和·P1_11引脚设置为CAN FD功能。   cAN通讯程序较为复杂,直接构建较为麻烦,所以通常使用工具自动生成程序。 if ((node_type == 'A') || (node_type == 'a')) { uint8_t index = 0; uint32_t times = 0; LOG_INFO("Please input the number of CAN/CANFD messages to be send and end with enter.\r\n"); while (index != 0x0D) { index = GETCHAR(); if ((index >= '0') && (index <= '9')) { (void)PUTCHAR(index); times = times * 10 + (index - 0x30U); } } LOG_INFO("\r\n"); txFrame.id = FLEXCAN_ID_STD(TX_MB_ID); txFrame.format = (uint8_t)kFLEXCAN_FrameFormatStandard; txFrame.type = (uint8_t)kFLEXCAN_FrameTypeData; txFrame.length = (uint8_t)DLC; #if (defined(USE_CANFD) && USE_CANFD) txFrame.brs = 1U; txFrame.edl = 1U; #endif for (i = 1; i <= times; i++) { #if (defined(USE_CANFD) && USE_CANFD) (void)FLEXCAN_TransferFDSendBlocking(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, &txFrame); #else (void)FLEXCAN_TransferSendBlocking(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, &txFrame); #endif /* Wait for 200ms after every 2 RX_QUEUE_BUFFER_SIZE transmissions. */ if ((TxCount % (RX_QUEUE_BUFFER_SIZE * 2U)) == 0U) SDK_DelayAtLeastUs(200000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); txFrame.dataByte0++; TxCount++; } LOG_INFO("Transmission done.\r\n\r\n"); } else { /* Wait until Rx queue 1 full. */ while (rxQueue1Flag != 1U) { }; rxQueue1Flag = 0; LOG_INFO("Read Rx MB from Queue 1.\r\n"); for (i = 0; i < RX_QUEUE_BUFFER_SIZE; i++) { LOG_INFO("Rx MB ID: 0x%3x, Rx MB data: 0x%x, Time stamp: %d\r\n", rxFrame[i].id >> CAN_ID_STD_SHIFT, rxFrame[i].dataByte0, rxFrame[i].timestamp); } /* Wait until Rx queue 2 full. */ while (rxQueue2Flag != 1U) { }; rxQueue2Flag = 0; LOG_INFO("Read Rx MB from Queue 2.\r\n"); for (; i < (RX_QUEUE_BUFFER_SIZE * 2U); i++) { LOG_INFO("Rx MB ID: 0x%3x, Rx MB data: 0x%x, Time stamp: %d\r\n", rxFrame[i].id >> CAN_ID_STD_SHIFT, rxFrame[i].dataByte0, rxFrame[i].timestamp); } if (rxStatus == kStatus_FLEXCAN_RxOverflow) { rxStatus = 0; LOG_INFO("The data in the last MB %d in the queue 2 is overwritten\r\n", RX_QUEUE_BUFFER_END_2); } LOG_INFO("Wait Node A to trigger the next 8 messages!\r\n\r\n"); } 主要思路为设置一个贞缓冲,使用FLEXCAN_TransferSendBlocking进行数据发送。接收数据使用中断进行接收数据。将接受数据放置到接收缓冲当中。 void EXAMPLE_FLEXCAN_IRQHandler(void) { User_TransferHandleIRQ(EXAMPLE_CAN); SDK_ISR_EXIT_BARRIER; } 3、测试过程 将两个开发板使用杜邦线相连。将开发板FRDM-MCXA156 USB线缆插入PC主机。   打开Putty中断,将开发板设置为节点NODE B     将FRDM-MCXN947 USB线缆插入PC,打开终端软件,将开发板设置为NODE  A 在终端中输入数据缓冲大小,可以发现由NODE A向NODE B发送的测试数据。   4、总结 从程序的编写角度来看,CAN的通讯较为复杂,调用的API也较多。虽然NXP对SDK进行了较大的简化,但是在复杂的应用中还是较为困难。如果业界推出一些较为程式化的封装库,则可以大大简化编程。就如iwIP之类的应用。    

  • 2025-01-21
  • 发表了主题帖: 【FRDM-MCXN947测评】AD采集和设置测试及功耗测量

    1、测试介绍 本测试使用ADC外设中断模式采集电压数据。MCXN947VDF MCU有两组16bit ADC核心。 1)每个 ADC 可用作两个单端输入 ADC 或一个差分输入 ADC。 2)在 16 位模式下高达 2 Msps,在 12 位模式下高达 3.15 Msps。 3)多达 75 个 ADC 输入通道。 4)每个 ADC 外设集成一个温度传感器作为温度补偿使用。 通常的MCU中多数为12bit的ADC,很少集成为16bit的ADC。所以MCXN947VDF使用为高档仪表较为理想。 硬件: FRDM-MCXN947一块。 USB type-c电缆线一条。 简易电压信号发生器一台。 万用表一块。 软件: GCC ARM Embedded 13.2.1编译器。 测试通过J8端口 28引脚采集电压。该引脚与MCU P4_23通道连接,本次测试使用14bit模式进行采集。     2、程序与测试设置 将MCU的ADC0的通道A2打开。   编写中断和初始化程序 中断服务程序。程序中使用LPADC_GetConvResult()函数获得ADC转化值。并且将g_LpadcConversionCompletedFlag = true;标记置为true用来提示采集完成。 void DEMO_LPADC_IRQ_HANDLER_FUNC(void) { g_LpadcInterruptCounter++; #if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) if (LPADC_GetConvResult(DEMO_LPADC_BASE, &g_LpadcResultConfigStruct, 0U)) #else if (LPADC_GetConvResult(DEMO_LPADC_BASE, &g_LpadcResultConfigStruct)) #endif /* FSL_FEATURE_LPADC_FIFO_COUNT */ { g_LpadcConversionCompletedFlag = true; } SDK_ISR_EXIT_BARRIER; } ADC初始化代码,代码的配置是通过mLpadcConfigStruct数据结构在各配置函数中进行传递。 1)LPADC_GetDefaultConfig(&mLpadcConfigStruct);函数取得默认配置,填充默认值。 2)对mLpadcConfigStruct各域进行赋值,即进行设置。 将预制值打开 选择参考电压源 选择均值模式 初始化ADC LPADC_GetDefaultConfig(&mLpadcConfigStruct); mLpadcConfigStruct.enableAnalogPreliminary = true; #if defined(DEMO_LPADC_VREF_SOURCE) mLpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE; #endif /* DEMO_LPADC_VREF_SOURCE */ #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS mLpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage128; #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */ LPADC_Init(DEMO_LPADC_BASE, &mLpadcConfigStruct); 设置采集模式和校准ADC。 /* Request LPADC calibration. */ #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE LPADC_SetOffsetCalibrationMode(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_CALIBRATION_MODE); #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */ #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS #if defined(DEMO_LPADC_DO_OFFSET_CALIBRATION) && DEMO_LPADC_DO_OFFSET_CALIBRATION LPADC_DoOffsetCalibration(DEMO_LPADC_BASE); /* Request offset calibration, automatic update OFSTRIM register. */ #else /* Update OFSTRIM register manually. */ #if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM #if defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 2U) LPADC_SetOffsetValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B); #elif defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 1U) LPADC_SetOffsetValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE); #endif /* FSL_FEATURE_LPADC_OFSTRIM_COUNT */ #else /* For other OFSTRIM register type. */ if (DEMO_LPADC_OFFSET_CALIBRATION_MODE == kLPADC_OffsetCalibration12bitMode) { LPADC_SetOffset12BitValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B); } else { LPADC_SetOffset16BitValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B); } #endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */ #endif /* DEMO_LPADC_DO_OFFSET_CALIBRATION */ #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFS */ #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ /* Request auto calibration (including gain error calibration and linearity error calibration). */ LPADC_DoAutoCalibration(DEMO_LPADC_BASE); #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ */ #if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS) /* Do auto calibration. */ LPADC_DoAutoCalibration(DEMO_LPADC_BASE); #endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */ #if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS) /* Do auto calibration. */ LPADC_DoAutoCalibration(DEMO_LPADC_BASE); #endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */ /* Set conversion CMD configuration. */ LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct); mLpadcCommandConfigStruct.channelNumber = DEMO_LPADC_USER_CHANNEL; #if defined(DEMO_LPADC_USE_HIGH_RESOLUTION) && DEMO_LPADC_USE_HIGH_RESOLUTION mLpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh; #endif /* DEMO_LPADC_USE_HIGH_RESOLUTION */ LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID, &mLpadcCommandConfigStruct); /* Set trigger configuration. */ LPADC_GetDefaultConvTriggerConfig(&mLpadcTriggerConfigStruct); mLpadcTriggerConfigStruct.targetCommandId = DEMO_LPADC_USER_CMDID; /* CMD15 is executed. */ mLpadcTriggerConfigStruct.enableHardwareTrigger = false; LPADC_SetConvTriggerConfig(DEMO_LPADC_BASE, 0U, &mLpadcTriggerConfigStruct); /* Configurate the trigger0. */ /* Enable the watermark interrupt. */ #if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) LPADC_EnableInterrupts(DEMO_LPADC_BASE, kLPADC_FIFO0WatermarkInterruptEnable); #else LPADC_EnableInterrupts(DEMO_LPADC_BASE, kLPADC_FIFOWatermarkInterruptEnable); #endif /* FSL_FEATURE_LPADC_FIFO_COUNT */ EnableIRQ(DEMO_LPADC_IRQn); PRINTF("ADC Full Range: %d\r\n", g_LpadcFullRange); 3、测试过程 将J8的28pin和GND短接进行测试。   经过多次测试,发现电压的范围变化不是很大。最高不超过2,2*3.3/4096=1.6mV毫伏。如果做平均则可以几乎接近为0V电压。 将J8接口28pin与信号发生器输出相接,信号输出设置为1.5V,输出如下:   大致在1961附近跳动,理论电压为1961*3.3/4096=1.579V,由于参考电压VDD_ANA为电源电压直接连接。所以对实际的电压进行测量为:3.27V   1961*3.27/4096=1.5655V,从测量来看,电压的精度一般。信号发生器的输出1.5014V(万用表测量值)。     使用的是lpADC设备,顺便测量了一下功耗,16.49*3.27=53.9mW,ADC和串口的共同功耗为53.9毫瓦。   4、总结 本次测试ADC从数值分析ADC的精度不是十分理想(也可以是无法获得实际参考电压的原因),功耗也较低功耗应用有一定的差距。本次的测试也可以受限测量方法的原因,所以有知道的请告知。  

  • 2025-01-19
  • 发表了主题帖: 【FRDM-MCXN947测评】DAC数模转换测试

    1、测试介绍 MCXN947VDF MCU有两组DAC通道,12bit 2个,14bit 1个本次使用测试的是DAC0通道,测试通过中断进行设置操作,通过串口进行修改测试电压值的操作。 硬件:FRDM-MCXN947开发板,万用表。 软件:GCC ARM Embedded 13.2.1编译器。不知道这个编译器版本是绑定的,在VScode中无法更换。             Putty串口终端软件。  通过J1接口的4_2pin输出。    2、测试过程 程序项目参考dac_1_buffer_interrupt样例 使用vscode打开项目   使用Putty软件连接串口。   通过putty终端进行修改电压值   电压最低值:0.0095,最高值:2.484,输出基本上稳定。 3、软件设计 软件步骤: 1、初始化DAC设备 2、启动DAC设备 3、启动DAC中断 /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_debug_console.h" #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_dac.h" /******************************************************************************* * Definitions ******************************************************************************/ #define DEMO_DAC_BASEADDR DAC0 #define DEMO_DAC_IRQ_ID DAC0_IRQn #define DEMO_DAC_IRQ_HANDLER_FUNC DAC0_IRQHandler #define DEMO_DAC_VREF kDAC_ReferenceVoltageSourceAlt1 #define DEMO_DAC_VALUE_ARRAY_SIZE 32U /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_DacInputIndex = 0U; volatile uint32_t g_DacOutputIndex = 0U; volatile uint32_t g_DacInterruptDone = false; /* User-defined wave for DAC output. */ const uint32_t g_DacValues[DEMO_DAC_VALUE_ARRAY_SIZE] = { 0U, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100}; /******************************************************************************* * Code ******************************************************************************/ /*! * [url=home.php?mod=space&uid=159083]@brief[/url] Main function */ int main(void) { dac_config_t dacConfigStruct; /* attach FRO 12M to FLEXCOMM4 (debug console) */ CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u); CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); /* attach FRO HF to DAC0 */ CLOCK_SetClkDiv(kCLOCK_DivDac0Clk, 1u); CLOCK_AttachClk(kFRO_HF_to_DAC0); /* enable DAC0 and VREF */ SPC0->ACTIVE_CFG1 |= 0x11; BOARD_InitPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); EnableIRQ(DEMO_DAC_IRQ_ID); /* Enable interrupt in NVIC. */ PRINTF("\r\nDAC buffer interrupt Example.\r\n"); /* Configure the DAC. */ DAC_GetDefaultConfig(&dacConfigStruct); dacConfigStruct.referenceVoltageSource = DEMO_DAC_VREF; dacConfigStruct.fifoTriggerMode = kDAC_FIFOTriggerBySoftwareMode; /* Software trigger. */ dacConfigStruct.fifoWorkMode = kDAC_FIFOWorkAsNormalMode; /* Normal FIFO mode. */ dacConfigStruct.fifoWatermarkLevel = 4U; /* Watermark. */ DAC_Init(DEMO_DAC_BASEADDR, &dacConfigStruct); DAC_Enable(DEMO_DAC_BASEADDR, true); /* Enable output. */ PRINTF("Press any key to trigger the DAC...\r\n"); /* Enable DAC interrupts. */ DAC_EnableInterrupts(DEMO_DAC_BASEADDR, kDAC_FIFOEmptyInterruptEnable); while (1) { /* Wait */ while (!g_DacInterruptDone) { } g_DacInterruptDone = false; /* Trigger the buffer and move the pointer. */ GETCHAR(); DAC_DoSoftwareTriggerFIFO(DEMO_DAC_BASEADDR); PRINTF("DAC next output: %d\r\n", g_DacValues[g_DacOutputIndex]); if (g_DacOutputIndex >= DEMO_DAC_VALUE_ARRAY_SIZE - 1U) { g_DacOutputIndex = 0U; } else { g_DacOutputIndex++; } } } /*! * @brief IRQ function for DAC buffer interrupt */ void DEMO_DAC_IRQ_HANDLER_FUNC(void) { uint32_t flags = DAC_GetStatusFlags(DEMO_DAC_BASEADDR); if (0U != (kDAC_FIFOEmptyFlag & flags)) { DAC_SetData(DEMO_DAC_BASEADDR, g_DacValues[g_DacInputIndex]); if (g_DacInputIndex >= (DEMO_DAC_VALUE_ARRAY_SIZE - 1U)) { g_DacInputIndex = 0U; } else { g_DacInputIndex++; } } g_DacInterruptDone = true; SDK_ISR_EXIT_BARRIER; } 4、刷新DAC_DoSoftwareTriggerFIFO(DEMO_DAC_BASEADDR);输入输出堆列。 中断中修改value /*! * @brief IRQ function for DAC buffer interrupt */ void DEMO_DAC_IRQ_HANDLER_FUNC(void) { uint32_t flags = DAC_GetStatusFlags(DEMO_DAC_BASEADDR); if (0U != (kDAC_FIFOEmptyFlag & flags)) { DAC_SetData(DEMO_DAC_BASEADDR, g_DacValues[g_DacInputIndex]); if (g_DacInputIndex >= (DEMO_DAC_VALUE_ARRAY_SIZE - 1U)) { g_DacInputIndex = 0U; } else { g_DacInputIndex++; } } g_DacInterruptDone = true; SDK_ISR_EXIT_BARRIER; } 通过 DAC_SetData(DEMO_DAC_BASEADDR, g_DacValues[g_DacInputIndex]);数组修改DAC的输出值。 4、总结 本次测试通过中断修改DAC的输出数值,当DAC完成输出后即使通过FIFO队列输出数据。NXP的DAC中断设计相当的完善,可以防止DAC输出出现间断的可能。  

  • 2025-01-08
  • 回复了主题帖: 【测评入围名单(最后1批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~

    个人信息无误,确认可以完成测评计划

  • 发表了主题帖: NXP MCUXpresso for VSCode插件安装编译工具故障

    故障描述: 因为在我的PC上有其它友商的环境,所以预先安装了arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi编译环境,并且设置了环境变量,%ARM_GCC_TOOLCHAIN_PATH%添加到PATH当中,而且工作良好,可以编译。使用MCUXpresso Installer安装工具安装软件, ARM_GCC_TOOLCHAIN_PATH D:\arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi\bin %ARM_GCC_TOOLCHAIN_PATH% MCUXpresso Installer安装工具显示如下:   MCUXpresso Installer安装工具也没有重新安装编译工具。 安装vscode插件   已经可以使用。使用配置工具   也输出正常。 但是,在使用插件导入项目时出现故障。   无法找到编译工具。即使指定目录也不行   出现故障   项目无法引入。 先后进行了两次安装均未成功。 但是如果将编译工具删除后,使用上述步骤可以安装成功。不知道是何原因。  

  • 2025-01-07
  • 回复了主题帖: 最近“具身智能”的概念很火,车厂们纷纷布局,大家怎么看?

    AI数学模型没有突破,机器人的时代就还很遥远

  • 2025-01-06
  • 加入了学习《Follow me第二季第3期 任务汇总》,观看 Follow me第二季第3期 任务汇总

  • 2025-01-01
  • 回复了主题帖: 电源PCB设计上,有哪些常见的坑?

    1、尽可能的不要使用PCB走220V等这样的信号,即时不得已也要注意趴电的距离或挖孔处理 2、即使是低速的板子中PCB的走线距离也不应该非常的长,长的走线可能带来干扰,例如:DC/DC的FB反馈线尽量不要原理芯片,其实这个信号的速度非常的高。因为,上升或下降沿非常的抖,就不应该看作是低速信号  

  • 回复了主题帖: 祝福2025!回帖即有奖!选取最有心的送5块国产开发板!

    感谢EEWORLD陪我度过了2024年,在2024年里个人生活起起伏伏经历了太多的故事,苦楚中有着不屈的奋斗。EEWORLD就像一杯清茶,虽然不能果腹但却给生活带来了许多的清新。祝愿各位网友2025大吉大利!EEWORLD越来越好!

  • 2024-12-31
  • 回复了主题帖: Linux下克隆github项目失败怎么办?

    linux也可以使用zip包的,wget 、curl都可以使用。get下包之后。如果实在不行就找人代劳

  • 2024-12-25
  • 回复了主题帖: 固态继电器关断不彻底的原因是什么?

    交流固态继电器是使用双向可控硅结构的,可以控制交流不可以控制直流,直流固态继电器可以控制直流,而不能控制交流,互不通用。

  • 回复了主题帖: KEIL编译USB功能异常IAR编译正常

    shipeng 发表于 2024-12-25 11:20 不对吧,如果是代码问题那IAR编译生成的目标文件也应该有问题才对,现在是用IAR编译功能是正常的。 可能原始项目是由IAR编写,所以在项目中的编译或链接参数是被修改了,keil就不一定了  

  • 加入了学习《【Follow me第二季第4期】ARDUINO NANO RP2040 CONNECT》,观看 Arduino NANO RP2040演示合集

  • 回复了主题帖: #源来如此#讨论场来啦~征集电源话题,说说你最关心最想知道的电源内容~

    变压器设计中电感对变压器的影响

统计信息

已有1204人来访过

  • 芯积分:5364
  • 好友:10
  • 主题:569
  • 回复:2374

留言

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


现在还没有留言