i.MX RT Crossover MCUs Knowledge Base

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

i.MX RT Crossover MCUs Knowledge Base

ディスカッション

ソート順:
1 Introduction RT1060 MCUXpresso SDK provide the ota_bootloader project, download link: https://mcuxpresso.nxp.com/en/welcome ota_bootloader path: SDK_2_10_0_EVK-MIMXRT1060\boards\evkmimxrt1060\bootloader_examples\ota_bootloader  this ota_bootloader can let the customer realize the on board app update, the RT1060 OTA bootloader mainly have the two functions: ISP method update APP Provide the API to the customer, can realize the different APP swap and rollback function ISP method is from the flashloader, the flashloader put the code in the internal RAM, when use it, normally RT chip need to enter the serial download mode, and use the sdphost download the flashloader to the internal RAM, then run it to realize the ISP function. But OTA_bootloader will put the code in the flash directly, RT chip can run it in the internal boot mode directly, each time after chip reset, the code will run the ota_bootloader at first, this time, customer can use the blhost to communicate the RT chip with UART/USB HID directly to download the APP code. So, to the ISP function in the OTA_bootloader, customer also can use it as the ISP secondary bootloader to update the APP directly. Then reset after the 5 seconds timeout, if the APP area is valid, code will jump to the APP and run APP. To the ota_bootloader swap and rollback function, customer can use the provided API in the APP directly to realize the APP update, run the different APP, swap and rollback to the old APP.    This document will give the details about how to use the ota_bootloader ISP function to update the APP, how to modify the customer application to match the ota_bootloader, how to resolve the customer APP issues which need to use the SDRAM with the ota_bootloader, how to use the ota_bootloader API to realize the swap and rollback function, and the related APP prepare. 2 OTA bootloader ISP usage Some customers need the ISP secondary bootloader function, as the flashloader need to put in the internal RAM, so customer can use the ota_bootloader ISP function realize the secondary bootloader requirement, to this method, customer mainly need to note two points: 1) APP need to add the ota_header to meet the ota_bootloader demand. 2) APP use the SDRAM, ota_bootloader need to add DCD memory  2.1 application modification OTA_bootloader located in the flash from 0x60000000, APP locate from 0x60040000. We can find this from the ota_bootloader bootloader_config.h file: #define BL_APP_VECTOR_TABLE_ADDRESS (0x60040000u) From 0x60040000, the first 0X400 should put the ota_header, then the real APP code is put from 0x60040400. Now, take the SDK evkmimxrt1060_iled_blinky project as an example, to modify it to match the ota_bootloader. Application code need to add these files: ota_bootloader_hdr.c, ota_bootloader_board.h, ota_bootloader_supp.c, ota_bootloader_supp.h These files can be found from the evkmimxrt1060_lwip_httpssrv_ota project, put the above files in the led_blinky source folder. 2.1.1 memory modification    APP memory start address modify from 0x60000000 to 0x60040000, which is the ota_bootloader defined address。 Fig 1 2.1.2 ota_hdr related files add   In the led_blinky project source folder, add the mentioned ota_bootloader related files. Fig 2 2.1.3 linker file modification In the evkmimxrt1060_iled_blinky_debug.ld, add boot_hdr, length is 0X400. We can use the MCUXpresso IDE linkscripts folder, add the .ldt files to modify the linker file. Here, in the project, add one linkscripts folder, add the boot_hdr_MIMXRT1060.ldt file, build . Fig 3 After the build, we can find the ld file already add the ota_header in the first 0x400 range. Fig 4 The above is the generated evkmimxrt1060_iled_blinky_ota_0x60040000.bin file, we can find already contains the boot_hdr. From offset 0x400, will put the real APP code. 2.2 ISP test related command Test board is MIMXRT1060-EVK, download the evkmimxrt1060_ota_bootloader project at first, can use the mcuxpresso IDE download it directly, then press the reset button, put the blhost and evkmimxrt1060_iled_blinky_ota_0x60040000.bin in the same folder, use the following command:   blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0 blhost.exe -t 2048000 -u 0x15a2,0x0073 -j -- flash-erase-region 0x60040000 0x6000 9 blhost.exe -t 5242000 -u 0x15a2,0x0073 -j -- write-memory 0x60040000 evkmimxrt1060_iled_blinky_ota_0x60040000.bin blhost.exe -t 5242000 -u 0x15a2,0x0073 -j -- read-memory 0x60040000 0x6000 flexspiNorCfg.dat 9 Fig 5 After the download is finished, press the reset, wait 5 seconds, it will jump to the app, we can find the MIMXRT1060-EVK on board led is blinking. This method realize the flash ISP bootloader downloading and the app working. The above command is using the USB HID to download, if need to use the UART, also can use command like this: blhost.exe -t 50000 -p COM45,19200 -j -- get-property 1 0 blhost.exe -t 50000 -p COM45,19200 -j -- flash-erase-region 0x60040000 0x6000 9 blhost.exe -t 50000 -p COM45,19200 -j -- write-memory 0x60040000 evkmimxrt1060_iled_blinky_ota_0x60040000.bin blhost.exe -t 50000 -p COM45,19200 -j -- read-memory 0x60040000 0x6000 flexspiNorCfg.dat 9 To the UART communication, as the ota_bootloader auto baud detect issues, it’s better to use the baudrate not larger than 19200bps, or in the ota_bootloader code, define the fixed baudrate, eg, 115200. 2.3 Bootloader DCD consideration Some customer use the ota_bootloader to associate with their own application, which is used the external SDRAM, and find although the downloading works, but after boot, the app didn’t run successfully. In the APP code, it add the DCD configuration, but as the ota_bootloader already put in the front of the QSPI, app will use the ota_hdr, which will delete the dcd part, so, to this situation, customer can add the dcd in the ota_bootloader. The SDK ota_bootloader didn’t add the dcd part in default. Now, modify the ota_bootloader at first, then prepare the sdram app and test it. 2.3.1 Ota_bootloader add dcd 2.3.1.1 add dcd files   ota_bootloader add dcd.c dcd.h, these two files can be found from the SDK hello_world project. Copy these two files to the ota_bootloader board folder. From the dcd.c code, we can see, dcd_data[] array is put in the “.boot_hdr.dcd_data” area, and it need to define the preprocessor: XIP_BOOT_HEADER_DCD_ENABLE=1 2.3.1.2 add dcd linker code   Modify the mcuxpresso IDE ld files, and add the dcd range.    .ivt : AT(ivt_begin) { . = 0x0000 ; KEEP(* (.boot_hdr.ivt)) /* ivt section */ . = 0x0020 ; KEEP(* (.boot_hdr.boot_data)) /* boot section */ . = 0x0030 ; KEEP(*(.boot_hdr.dcd_data)) __boot_hdr_end__ = ABSOLUTE(.) ; . = 0x1000 ; } > m_ivt Fig 6 0x60001000 : IVT 0x6000100c : DCD entry point 0x60001020 : boot data 0x60001030 : DCD detail data 2.3.1.3 add IVT dcd entry point   ota_bootloader->MIMXRT1062 folder->hardware_init_MIMXRT1062.c,modify the image_vector_table, fill the DCD address to the dcdc_data array address as the dcd entry point. Fig 7 Until now, we finish the ota_bootloader dcd add, build the project, generate the image, we can find, DCD already be added to the ota_bootloader image. Fig 8 DCD entry point in the IVT and the DCD data is correct, we can burn this modified ota_bootloader to the MIMXRT1060-EVK board. 2.3.2 SDRAM app prepare Still based on the evkmimxrt1060_iled_blinky project, just put some function in the SDRAM. From memory, we can find, the SRAM is in the RAM4: Fig 9 In the led_blinky.c, add this header: #include <cr_section_macros.h> Then, put the systick delay code to the RAM4 which is the SDRAM area. __RAMFUNC(RAM4) void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } Now, we already finish the simple SDRAM app, we also can test it, and put the breakpoint in the SysTick_DelayTicks, we can find the address is also the SDRAM related address, generate the evkmimxrt1060_iled_blinky1_SDRAM_0x60040000.bin. If use the old ota_bootloader to download this .bin, we can find the led is not blinking. 2.3.3 Test result Command refer to chapter 2.2 ISP test related command, download the evkmimxrt1060_iled_blinky1_SDRAM_0x60040000.bin with the new modified ota_bootloader project, we can find, after reset, the led will blink. So the SDRAM app works with the modified ota_bootloader. 3 OTA bootloader swap and rollback OTA bootloader can realize the swap and rollback function, this part will test the ota_bootloader swap and rollback, prepare two apps and download to the different partition area, then use the UART input char to select the swap or rollback function, to check the which app is running. 3.1  memory map ota bootloader memory information. Fig 10 The above map is based on the external 8Mbyte QSPI flash. OTA bootloader: RT SDK ota bootloader code Boot meta 0: contains 3 partition start address, size etc. information, ISP peripheral information. Boot meta 1: contains 3 partition start address, size etc. information, ISP peripheral information. Swap meta 0: bootloader will use meta data to do the swap operation Swap meta 1: bootloader will use meta data to do the swap operation Partition 1: APP1 location Partition 2: APP2 location Scratch part: APP1 backup location, start point is before 0x60441000, which is enough to put APP1 and multiple sector size, eg, APP1 is 0X5410, sector size is 0x1000, APP1 need 6 sectors, so the scratch start address is 0x60441000-0x6000=0x43b000. User data: user used data area 3.2 swap and rollback basic Fig11  The APP1 and APP2 put in the partition1 and partition2 need to contains the ota_header which meet the bootloader demand, bootloader will check the APP CRC, if it passed, then will boot the app, otherwise, it will enter the ISP mode. Partition2 image need to has the valid header, otherwise, swap will be failed.   Swap function will erase partition2 scratch area, then put the partition1 code to the scratch, erase the partition 1 position, and write the partition 2 image to the partition1 position.   Rollback function will run the previous APP1, erase the partition 2 position, copy the parititon 1 image back to the partition 2, erase partition 1 position, copy partition 2 scratch image back to partition 1. 3.2.1 boot meta boot_meta 0: 0x0x6003c000 size: 0x20c boot_meta 1: 0x0x6003d000 size: 0x20c   OTA bootloader can read boot meta from the two different address, when the two address meta are valid(tag is 'B', 'L', 'M', 'T'), bootloader will choose the bigger version meta. If both meta is not valid, bootloader will copy default boot meta data to the boot meta 0 address.   Boot meta contains 3 partition start address, size information. SDK demo can call bootloader API to find the partition information, then do the image program.   Boot meta also contains the ISP peripheral information, the timeout(5s) information, the structure is: //!@brief Partition information table definitions typedef struct { uint32_t start; //!< Start address of the partition uint32_t size; //!< Size of the partition uint32_t image_state; //!< Active/ReadyForTest/UnderTest uint32_t attribute; //!< Partition Attribute - Defined for futher use uint32_t reserved[12]; //!< Reserved for future use } partition_t; //!@brief Bootloader meta data structure typedef struct { struct { uint32_t wdTimeout; uint32_t periphDetectTimeout; uint32_t enabledPeripherals; uint32_t reserved[12]; } features; partition_t partition[kPartition_Max];//16*4*7 bytes uint32_t meta_version; uint32_t patition_entries; uint32_t reserved0; uint32_t tag; } bootloader_meta_t;   3.2.2 swap meta Swap meta 0 : 0x6003e000, size 0x50 Swap meta 1 : 0x6003f000, size 0x50    OTA bootloader will read the swap meta from 2 different place, if it is not valid, bootloader will set the default data to swap meta 0(0x6003e000). If both image are valid, bootloader will choose the bigger version meta.    Bootloader will refer to the meta data to do the swap operation, sometimes, after reset, meta data will be modified automatically. It mainly relay on the swap_type: kSwapType_ReadyForTest :After reset, do swap operation. Modify meta swap_type to kSwapType_Test. Reset, as the meta data is kSwapType_Test, bootloader can do the rollback. kSwapType_Test : After reset, do rollback after operation, swap_type change to kSwapType_None.  kSwapType_Rollback bootloader will write kSwapType_Test to the meta, after reset, bootloader will refer to kSwapType_Test to do the operation.  kSwapType_Permanent After reset, modify meta data to kSwapType_Permanent, then the APP will boot with partition 1. Swap structure: //!@brief Swap progress definitions typedef struct { uint32_t swap_offset; //!< Current swap offset uint32_t scratch_size; //!< The scratch area size during current swapping uint32_t swap_status; // 1 : A -> B scratch, 2 : B -> A uint32_t remaining_size; //!< Remaining size to be swapped } swap_progress_t; typedef struct { uint32_t size; uint32_t active_flag; } image_info_t; //!@brief Swap meta information, used for the swapping operation typedef struct { image_info_t image_info[2]; //!< Image info table #if !defined(BL_FEATURE_HARDWARE_SWAP_SUPPORTED) || (BL_FEATURE_HARDWARE_SWAP_SUPPORTED == 0) swap_progress_t swap_progress; //!< Swap progress #endif uint32_t swap_type; //!< Swap type uint32_t copy_status; //!< Copy status uint32_t confirm_info; //!< Confirm Information uint32_t meta_version; //!< Meta version uint32_t reserved[7]; //!< Reserved for future use uint32_t tag; } swap_meta_t; 3.3 Common used API Bootloader provide the API for the customer to use it, the common used API are: 3.3.1 update_image_state   update swap meta data, before update, it will check the partition1 image valid or not, if image is not valid, swap meta data will not be updated, and return failure. 3.3.2 get_update_partition_info   get partition information, then define the image program address. 3.3.3 get_image_state   get the current boot image status. None/permanent/UnderTest 3.4  Swap rollback APP prepare Prepare two APPs: APP1 and APP2 bin file, and use the USB HID download to the partition1 and paritition 2. After reset, run APP1 in default, then use the COM input to select the swap and rollback function. Code is: int main(void) { char ch; status_t status; /* Board pin init */ BOARD_InitPins(); BOARD_InitBootClocks(); /* Update the core clock */ SystemCoreClockUpdate(); BOARD_InitDebugConsole(); PRINTF("\r\n------------------hello world + led blinky demo 2.------------------\r\n"); PRINTF("\r\nOTA bootloader test...\r\n" "1 - ReadyForTest\r\n" "3 - kSwapType_Permanent\r\n" "4 - kSwapType_Rollback\r\n" "5 - show image state\r\n" "6 - led blinking for 5times\r\n" "r - NVIC reset\r\n"); // show swap state in swap meta get_image_swap_state(); /* Set systick reload value to generate 1ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while(1) { ch = GETCHAR(); switch(ch) { case '1': status = bl_update_image_state(kSwapType_ReadyForTest); PRINTF("update_image_state to kSwapType_ReadyForTest status: %i\n", status); if (status != 0) PRINTF("update_image_state(kSwapType_ReadyForTest): failed\n"); else NVIC_SystemReset(); break; case '3': status = bl_update_image_state(kSwapType_Permanent); PRINTF("update_image_state to kSwapType_Permanent status: %i\n", status); if (status != 0) PRINTF("update_image_state(kSwapType_Permanent): failed\n"); else NVIC_SystemReset(); break; case '4': status = bl_update_image_state(4); // PRINTF("update_image_state to kSwapType_Rollback status: %i\n", status); if (status != 0) PRINTF("update_image_state(kSwapType_Rollback): failed\n"); else NVIC_SystemReset(); break; case '5': // show swap state in swap meta get_image_swap_state(); break; case '6': Led_blink10times(); break; case 'r': NVIC_SystemReset(); break; } } } When download the APP, need to use the correct ota_header in the first 0x400 area, otherwise, swap will failed. const boot_image_header_t ota_header = { .tag = IMG_HDR_TAG, .load_addr = ((uint32_t)&ota_header) + BL_IMG_HEADER_SIZE, .image_type = IMG_TYPE_XIP, .image_size = 0, .algorithm = IMG_CHK_ALG_CRC32, .header_size = BL_IMG_HEADER_SIZE, .image_version = 0, .checksum = {0xFFFFFFFF}, }; This is a correct sample: Fig 12 Image size and checksum need to use the real APP image information, in the attached file, provide one image_header_padding.exe, it can input the none ota header image, then it will output the whole image which add the ota_header contains the image size and the image crc data in the first 0x400 range. 3.5 Test steps and result Prepare the none header APP1 evkmimxrt1060_APP1_0X60040400.bin, APP2 image evkmimxrt1060_APP2_0X60240400.bin, and put blhost.exe, image_header_padding.exe in the same folder. APP1 and APP2 just the printf version is different, one is version1, another is version2. Printf result: hello world + led blinky demo 1 hello world + led blinky demo 2 Attached OTAtest folder is used for test, but need to download the blhost.exe from the below link, and copy the blhost.exe to the OTAtest folder. https://www.nxp.com/webapp/sps/download/license.jsp?colCode=blhost_2.6.6&appType=file1&DOWNLOAD_ID=null Then run the following bat command: image_header_padding.exe evkmimxrt1060_APP1_0X60040400.bin 0x60040400 sleep 20 blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0 sleep 20 blhost.exe -u -t 1000000 -- flash-erase-region 0x6003c000 0x4000 sleep 50 blhost -u -t 5000 -- flash-erase-region 0x60040000 0x10000 sleep 50 blhost -u -t 5000 -- write-memory 0x60040000 boot_img_crc32.bin sleep 100 image_header_padding.exe evkmimxrt1060_APP2_0X60240400.bin 0x60040400 sleep 20 blhost -u -t 5000 -- flash-erase-region 0x60240000 0x10000 sleep 50 blhost -u -t 5000 -- flash-erase-region 0x6043b000 0x10000 sleep 50 blhost -u -t 5000 -- write-memory 0x60240000 boot_img_crc32.bin sleep 100 pause The function is to generate the APP1 with the correct ota_header, erase parititon 1,program APP1 to partition 1, generate the APP2 with the correct ota_header, erase partition 2 and scratch area, program APP2 to partition 2, Run the .bat file should in 5 seconds after reset, then use the ISP to connect it: blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0 ota_bootloader can use the ota_bootloader project download directly to the 0X60000000 area. After downloading, reset the chip, and wait for 5 seconds, the APP will run. This is the test result: Fig 13 From the test result, we can find, in the first time boot, APP1 running, image state: none Input 1, do the swap, will find the APP2 running, image state: undertest Input 3, select permanent, reset will find, still APP2 running, image state: permanent Input 4, choose rollback, reset will find APP1 running, image states: none Until now, finish the swap and rollback function. Input 6, will find the APP contains the SDRAM led blinky is working.          
記事全体を表示
1. Abstract This article aims to implement the simultaneous input of 4 groups of 48Khz 32bit 2ch audio data on the RT685 platform, and then assemble the received data into a 48Khz 32bit 8ch audio and output it through I2S. This solution is also done at the request of customers, because there are always harmonic problems when customers make it. After analyzing the customer's situation, it is found that the customer has two main problems: (1) Harmonic problem: After receiving 4 channels of 8 bytes, it is directly copied to the sending buffer. This will cause timing problems. It does not take into account the problem of buffering data in the audio data storage pool. The time required to receive enough audio data is at least greater than the time required for copying and sending. Therefore, the problem is reflected in the problem that the customer found harmonic problems when testing the output audio waveform. (2) Audio synchronization problem: After the customer received 4 channels of audio data, he tested the receiving buffer and found that the 4 channels of data were out of sync. Therefore, in order to help customers, I helped customers make this application demo directly, and made a matching test audio source to send a set of 48Khz sampling rate 32bit dual-channel, fixed increment audio data in a loop, such as 0X00-0XFF in a loop. The following is the block diagram of this application platform:   Figure 1 System Block Diagram In the above figure, a MIMXRT685-EVK implements the function of outputting 48Khz, 32bit*2ch, and sends data in a loop: 0X00, 0X01….0XFF. Another MIMXRT685-EVK is the focus of this article, which implements 4 groups of I2S to receive data at a sampling rate of 48khz and 32bit*2ch, and then assembles the received data into audio data with a sampling rate of 48Khz and 32bit*8ch and sends it out. In the above figure, in order to reduce the connection of external lines, for BCLK and WS signals, only one group is directly connected to I2S3, and the other I2S2, I2S4, and I2S5 share the I2S3 signal internally. Then, for DATA data, a line is made externally with 4 heads, and connected to the data pins of each group of audio interfaces respectively. The following is a detailed description of this solution. 2. Hardware platform establish The pinouts of the two boards are given below. Because the platform uses many pins, specific allocation is required. 2.1 Audio source board A MIMXRT685-EVK is used as an audio source, and the pinouts for sending 48Khz 32bit*2ch are as follows:   Figure 2 Pinout of audio source board 2.2 Audio transceiver board Another MIMXRT685-EVK is used as an audio transceiver board to receive 4-channel audio synchronization data sent by the audio source and assemble it into a 48Khz 32bit*8ch waveform for transmission.   Figure 3 Pin assignment of audio transceiver board 2.3 Dual-board hardware connection The source and target connections of the two boards are as follows:   Figure 4 Two board pin connection   Figure 5 two board connection After the hardware is ready, the software solution and code are provided. 3. Software solution and software implementation In the process of writing the code, we tried many solutions, such as: (1) When receiving, directly assemble it into the TDM format buffer to be sent, and then send it. However, since it is assembled into TDM, one I2S needs to receive 8 byte per frame, and then do the offset to receive the next one. If the reception is carried out according to the 8-byte DMA, the callback of the 4 groups of I2S will enter frequently, resulting in a large CPU load, so this solution is abandoned. (2) The 4 groups of I2S are connected to each other, and the 10ms buffer is connected, and then the DMA method is used to copy from memory to memory. However, since the DMA of RT685 is relatively weak, it can only achieve a maximum offset of 32bit 4word=16byte, that is, a 16-byte offset. However, in fact, a group of audio data is 32bit*2, and 4 groups are 32bit*8=32byte offset, so DMA cannot meet the requirements. Therefore, the DMA memory-to-memory copy solution is abandoned and memcpy is used instead. (3) Use the I2S_RxTransferReceiveDMA function to perform DMA reception. However, in fact, when one group is called, it starts receiving directly, and waits until the next group of I2S interfaces calls I2S_RxTransferReceiveDMA. This has caused an asynchronous situation. Even if the I2S enable is turned off in I2S_RxTransferReceiveDMA, the 4th group of I2S is enabled after the several groups of I2S of I2S_RxTransferReceiveDMA are called. This method can only achieve the synchronization of the reception of the first group of data, because later, it is necessary to go to the callback to re-trigger the reception of the second frame of data. Therefore, the callback of the 4 groups of I2S calls I2S_RxTransferReceiveDMA, which will inevitably cause new synchronization problems. Therefore, this method is abandoned and it is considered to use two groups of DMA descriptors to do ping-pong. In this way, the reception will continue in a loop without the intervention of CPU code. 3.1 Solution Implementation Several solutions have been described above. Finally, we choose to use 4 audio channels to receive audio data and cache 10ms audio data buffer. The conversion from receiving buffer to sending buffer adopts memcpy method, and test whether this copy time can meet the actual needs, to ensure that the buffer pool of receiving buffer is greater than this copy time, which is enough to prepare the sending buffer. The solution for receiving data transfer is as follows:   Figure 6 Data buffer transfer The above is 4 groups of I2S receiving their own 10ms data respectively. The buffer is actually prepared for 20ms. A single DMA receives a frame for 10ms, and the other 10ms is used for pingpong buffer. The sending buffer is used to copy the received 4 groups of I2S buffers into a 32bit*8ch array in TDM format, and then two groups of ping-pong buffers are also made. In fact, it is to cache 10ms data. The buffer prepares two groups of 10ms. When the first 10ms frame is received, the second buffer is used to receive it. At the same time, the data of the first buffer is copied to the first buffer of the sending buffer, and the first buffer is used for sending. After the sending is completed, it is transferred to the second buffer to receive and send. In this way, as long as the time is controlled well, there will be no data error problem. The data volume of 10ms is 3840Byte, because the receiving frequency is 48Khz, that is, there are 48000 frames in 1s, and each frame is 32bit*2=8Byte, then 10ms=>4800*8Byte=38400Byte. 3.2 Software code implementation The software code implementation part is mainly divided into 4 I2S receiving signal sharing, I2S DMA pingpong configuration, data transfer, sending I2S and other parts. The details are given below 3.2.1 4-way I2S receiving From the above, we can know that the 4 I2S receiving signal is not completely connected with wires, but adopts the method of sharing BCLK and WS signals and receiving DATA separately. I2S2, I2S4, I2S5 share the BCLK of I2S3, and the WS code is as follows: /* Set shared signal set 0: SCK, WS from Flexcomm1 */ I2S_BRIDGE_SetShareSignalSrc(kI2S_BRIDGE_ShareSet0, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_Flexcomm3); I2S_BRIDGE_SetShareSignalSrc(kI2S_BRIDGE_ShareSet0, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_Flexcomm3); /* Set flexcomm3 SCK, WS from shared signal set 0 */ I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm2, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm2, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm4, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm4, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm5, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm5, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_ShareSet0); 3.2.2 I2S DMA pingpong configuration In order to achieve 4-channel audio synchronization and receive 10ms audio buffer, two I2S DMA descriptors are used to implement the ping-pong function to collect data to two ping-pong buffers in turn. The code is as follows: #define I2S_BUFFER_SIZE 3840 //10ms SDK_ALIGN(static dma_descriptor_t I2S2_s_rxDmaDescriptors[2U], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE); SDK_ALIGN(static dma_descriptor_t I2S3_s_rxDmaDescriptors[2U], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE); SDK_ALIGN(static dma_descriptor_t I2S4_s_rxDmaDescriptors[2U], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE); SDK_ALIGN(static dma_descriptor_t I2S5_s_rxDmaDescriptors[2U], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE); SDK_ALIGN(static uint8_t I2S2_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S3_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S4_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S5_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); static i2s_transfer_t I2S2_s_RxTransfer[2] = {{ .data = I2S2_s_Buffer[0], .dataSize = I2S_BUFFER_SIZE, }, { .data = I2S2_s_Buffer[1], .dataSize = I2S_BUFFER_SIZE, }}; static i2s_transfer_t I2S3_s_RxTransfer[2] = {{ .data = I2S3_s_Buffer[0], .dataSize = I2S_BUFFER_SIZE, }, { .data = I2S3_s_Buffer[1], .dataSize = I2S_BUFFER_SIZE, }}; static i2s_transfer_t I2S4_s_RxTransfer[2] = {{ .data = I2S4_s_Buffer[0], .dataSize = I2S_BUFFER_SIZE, }, { .data = I2S4_s_Buffer[1], .dataSize = I2S_BUFFER_SIZE, }}; static i2s_transfer_t I2S5_s_RxTransfer[2] = {{ .data = I2S5_s_Buffer[0], .dataSize = I2S_BUFFER_SIZE, }, { .data = I2S5_s_Buffer[1], .dataSize = I2S_BUFFER_SIZE, }}; I2S_RxGetDefaultConfig(&I2S2_s_RxConfig); I2S2_s_RxConfig.divider = DEMO_I2S_CLOCK_DIVIDER; I2S2_s_RxConfig.masterSlave = DEMO_I2S_TX_MODE;//DEMO_I2S_RX_MODE I2S_RxInit(DEMO_I2S2_RX, &I2S2_s_RxConfig); I2S_RxGetDefaultConfig(&I2S3_s_RxConfig); I2S3_s_RxConfig.divider = DEMO_I2S_CLOCK_DIVIDER; I2S3_s_RxConfig.masterSlave = DEMO_I2S_TX_MODE;//DEMO_I2S_RX_MODE I2S_RxInit(DEMO_I2S3_RX, &I2S3_s_RxConfig); I2S_RxGetDefaultConfig(&I2S4_s_RxConfig); I2S4_s_RxConfig.divider = DEMO_I2S_CLOCK_DIVIDER; I2S4_s_RxConfig.masterSlave = DEMO_I2S_TX_MODE;//DEMO_I2S_RX_MODE I2S_RxInit(DEMO_I2S4_RX, &I2S4_s_RxConfig); I2S_RxGetDefaultConfig(&I2S5_s_RxConfig); I2S5_s_RxConfig.divider = DEMO_I2S_CLOCK_DIVIDER; I2S5_s_RxConfig.masterSlave = DEMO_I2S_TX_MODE;//DEMO_I2S_RX_MODE I2S_RxInit(DEMO_I2S5_RX, &I2S5_s_RxConfig); DMA_Init(DEMO_DMA); DMA_EnableChannel(DEMO_DMA, DEMO_I2S2_RX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S2_RX_CHANNEL, kDMA_ChannelPriority1); DMA_CreateHandle(&I2S2_s_DmaRxHandle, DEMO_DMA, DEMO_I2S2_RX_CHANNEL); I2S_RxTransferCreateHandleDMA(DEMO_I2S2_RX, &I2S2_s_RxHandle, &I2S2_s_DmaRxHandle, I2S2_RxCallback, (void *)&I2S2_s_RxTransfer); DMA_EnableChannel(DEMO_DMA, DEMO_I2S3_RX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S3_RX_CHANNEL, kDMA_ChannelPriority1); DMA_CreateHandle(&I2S3_s_DmaRxHandle, DEMO_DMA, DEMO_I2S3_RX_CHANNEL); I2S_RxTransferCreateHandleDMA(DEMO_I2S3_RX, &I2S3_s_RxHandle, &I2S3_s_DmaRxHandle, I2S3_RxCallback, (void *)&I2S3_s_RxTransfer); DMA_EnableChannel(DEMO_DMA, DEMO_I2S4_RX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S4_RX_CHANNEL, kDMA_ChannelPriority1); DMA_CreateHandle(&I2S4_s_DmaRxHandle, DEMO_DMA, DEMO_I2S4_RX_CHANNEL); I2S_RxTransferCreateHandleDMA(DEMO_I2S4_RX, &I2S4_s_RxHandle, &I2S4_s_DmaRxHandle, I2S4_RxCallback, (void *)&I2S4_s_RxTransfer); DMA_EnableChannel(DEMO_DMA, DEMO_I2S5_RX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S5_RX_CHANNEL, kDMA_ChannelPriority2); DMA_CreateHandle(&I2S5_s_DmaRxHandle, DEMO_DMA, DEMO_I2S5_RX_CHANNEL); I2S_RxTransferCreateHandleDMA(DEMO_I2S5_RX, &I2S5_s_RxHandle, &I2S5_s_DmaRxHandle, I2S5_RxCallback, (void *)&I2S5_s_RxTransfer); I2S_TransferInstallLoopDMADescriptorMemory(&I2S2_s_RxHandle, I2S2_s_rxDmaDescriptors, 2U); I2S_TransferInstallLoopDMADescriptorMemory(&I2S3_s_RxHandle, I2S3_s_rxDmaDescriptors, 2U); I2S_TransferInstallLoopDMADescriptorMemory(&I2S4_s_RxHandle, I2S4_s_rxDmaDescriptors, 2U); I2S_TransferInstallLoopDMADescriptorMemory(&I2S5_s_RxHandle, I2S5_s_rxDmaDescriptors, 2U); if (I2S_TransferReceiveLoopDMA(DEMO_I2S2_RX, &I2S2_s_RxHandle, &I2S2_s_RxTransfer[0], 2U) != kStatus_Success) { assert(false); } if (I2S_TransferReceiveLoopDMA(DEMO_I2S3_RX, &I2S3_s_RxHandle, &I2S3_s_RxTransfer[0], 2U) != kStatus_Success) { assert(false); } if (I2S_TransferReceiveLoopDMA(DEMO_I2S4_RX, &I2S4_s_RxHandle, &I2S4_s_RxTransfer[0], 2U) != kStatus_Success) { assert(false); } if (I2S_TransferReceiveLoopDMA(DEMO_I2S5_RX, &I2S5_s_RxHandle, &I2S5_s_RxTransfer[0], 2U) != kStatus_Success) { assert(false); } I2S_Enable(DEMO_I2S2_RX); I2S_Enable(DEMO_I2S3_RX); I2S_Enable(DEMO_I2S4_RX); I2S_Enable(DEMO_I2S5_RX); Here, the code has been modified, mainly the I2S_TransferLoopDMA function in fsl_i2s_dma.c, which is blocked: I2S_Enable(base); In order to realize the function of 4-channel synchronous reception. 3.2.3 Audio data received and transferred Because when receiving, each audio interface takes turns to receive its own 2ch data, but when sending, it is necessary to send 4-channel received audio dual-channel data, that is, 32bit*8ch data, so after receiving ping, the ping data needs to be transferred to the sending ping buffer. The code for transfer is as follows: #define I2S_BUFFER_SIZE 3840 //10ms SDK_ALIGN(static uint8_t I2S2_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S3_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S4_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S5_s_Buffer[2][I2S_BUFFER_SIZE], sizeof(uint32_t)); SDK_ALIGN(static uint8_t I2S1_s_Buffer[2][I2S_BUFFER_SIZE*4], sizeof(uint32_t)); if( s_pingpong == 1) { for(ch = 0;ch < 480; ch++) //480=I2S_BUFFER_SIZE(3840)/8 { memcpy(&I2S1_s_Buffer[0][0 + (32*ch)], &I2S2_s_Buffer[0][8*ch], 8); memcpy(&I2S1_s_Buffer[0][8 + (32*ch)], &I2S3_s_Buffer[0][8*ch], 8); memcpy(&I2S1_s_Buffer[0][16 + (32*ch)], &I2S4_s_Buffer[0][8*ch], 8); memcpy(&I2S1_s_Buffer[0][24 + (32*ch)], &I2S5_s_Buffer[0][8*ch], 8); } } else { for(ch = 0;ch < 480; ch++) { memcpy(&I2S1_s_Buffer[1][0 + (32*ch)], &I2S2_s_Buffer[1][8*ch], 8); memcpy(&I2S1_s_Buffer[1][8 + (32*ch)], &I2S3_s_Buffer[1][8*ch], 8); memcpy(&I2S1_s_Buffer[1][16 + (32*ch)], &I2S4_s_Buffer[1][8*ch], 8); memcpy(&I2S1_s_Buffer[1][24 + (32*ch)], &I2S5_s_Buffer[1][8*ch], 8); } } 3.2.4 Send TDM audio code The sending code also uses the I2S DMA method, but because there is no need to send multiple channels at the same time, only a single channel, there is no need to consider the synchronization problem, and no DMA descriptor is used. After the sending buffer is ready, the I2S_TxTransferSendDMA method is used. The code is as follows: I2S_TxGetDefaultConfig(&I2S1_s_TxConfig); I2S1_s_TxConfig.divider = DEMO_I2S1_CLOCK_DIVIDER; I2S1_s_TxConfig.masterSlave = kI2S_MasterSlaveNormalMaster; I2S1_s_TxConfig.wsPol = true; I2S1_s_TxConfig.mode = kI2S_ModeDspWsLong;//kI2S_ModeDspWsShort; I2S1_s_TxConfig.dataLength = 32U; I2S1_s_TxConfig.frameLength = 32 * 8U; I2S1_s_TxConfig.position = DEMO_TDM_DATA_START_POSITION; I2S1_s_TxConfig.pack48 = true; I2S_TxInit(DEMO_I2S1_TX, &I2S1_s_TxConfig); I2S_EnableSecondaryChannel(DEMO_I2S1_TX, kI2S_SecondaryChannel1, false, 64 + DEMO_TDM_DATA_START_POSITION); I2S_EnableSecondaryChannel(DEMO_I2S1_TX, kI2S_SecondaryChannel2, false, 128 + DEMO_TDM_DATA_START_POSITION); I2S_EnableSecondaryChannel(DEMO_I2S1_TX, kI2S_SecondaryChannel3, false, 192 + DEMO_TDM_DATA_START_POSITION); DMA_EnableChannel(DEMO_DMA, DEMO_I2S1_TX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S1_TX_CHANNEL, kDMA_ChannelPriority3); DMA_CreateHandle(&I2S1_s_DmaTxHandle, DEMO_DMA, DEMO_I2S1_TX_CHANNEL); I2S_TxTransferCreateHandleDMA(DEMO_I2S1_TX, &I2S1_s_TxHandle, &I2S1_s_DmaTxHandle, I2S1_TxCallback, (void *)&I2S1_s_TxTransfer); if( s_pingpong == 1) { I2S1_s_TxTransfer.data = I2S1_s_Buffer[0]; I2S1_s_TxTransfer.dataSize = I2S_BUFFER_SIZE*4; I2S_TxTransferSendDMA(DEMO_I2S1_TX, &I2S1_s_TxHandle, I2S1_s_TxTransfer); } else { I2S1_s_TxTransfer.data = I2S1_s_Buffer[1]; I2S1_s_TxTransfer.dataSize = I2S_BUFFER_SIZE*4; I2S_TxTransferSendDMA(DEMO_I2S1_TX, &I2S1_s_TxHandle, I2S1_s_TxTransfer); } 3.2.5 Send and receive I2S callback processing For the receiving I2S2, 3, 4, 5, there are 4 channels in total. Each time 10ms of data is received, a callback will be entered. In the callback, you only need to record the flag. When all 4 flags are recorded, it means that the 4 channels of the same 10ms data have been received, and the data can be copied to the sending buffer. Of course, in order to test whether the callback entry frequency is once every 10ms, this article makes a GPIO callback for testing. The following is the code for recording I2S callback static void I2S2_RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { s_allRXTriggerred |= 0x01; } static void I2S3_RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { s_allRXTriggerred |= 0x02; } static void I2S4_RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { s_allRXTriggerred |= 0x04; } static void I2S5_RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { /* Enqueue the same original buffer all over again */ s_allRXTriggerred |= 0x08; GPIO_PortToggle(GPIO, 1, 1<<0); if( s_pingpong == 0) { s_pingpong = 1; } else { s_pingpong = 0; } } static void I2S1_TxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { GPIO_PortToggle(GPIO, 1, 1<<8); //__NOP(); } So far, all functions of a MIMXRT685-EVK for 4 I2S reception and 1 I2S TDM transmission have been completed. 3.2.6 Audio source code The audio source is made on another MIMXRT685-EVK to send 48Khz, 32bit*2ch audio data, and the data is sent in a loop from 0X00 to 0XFF. The code is as follows: int main(void) { BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); BOARD_I3C_ReleaseBus(); BOARD_InitI3CPins(); CLOCK_EnableClock(kCLOCK_InputMux); /* attach main clock to I3C (500MHz / 20 = 25MHz). */ CLOCK_AttachClk(kMAIN_CLK_to_I3C_CLK); CLOCK_SetClkDiv(kCLOCK_DivI3cClk, 20); /* attach AUDIO PLL clock to FLEXCOMM1 (I2S1) */ CLOCK_AttachClk(kAUDIO_PLL_to_FLEXCOMM1); /* attach AUDIO PLL clock to FLEXCOMM3 (I2S3) */ CLOCK_AttachClk(kAUDIO_PLL_to_FLEXCOMM3); /* attach AUDIO PLL clock to MCLK */ CLOCK_AttachClk(kAUDIO_PLL_to_MCLK_CLK); CLOCK_SetClkDiv(kCLOCK_DivMclkClk, 1); SYSCTL1->MCLKPINDIR = SYSCTL1_MCLKPINDIR_MCLKPINDIR_MASK; wm8904Config.i2cConfig.codecI2CSourceClock = CLOCK_GetI3cClkFreq(); wm8904Config.mclk_HZ = CLOCK_GetMclkClkFreq(); /* Set shared signal set 0: SCK, WS from Flexcomm1 */ I2S_BRIDGE_SetShareSignalSrc(kI2S_BRIDGE_ShareSet0, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_Flexcomm1); I2S_BRIDGE_SetShareSignalSrc(kI2S_BRIDGE_ShareSet0, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_Flexcomm1); /* Set flexcomm3 SCK, WS from shared signal set 0 */ I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm3, kI2S_BRIDGE_SignalSCK, kI2S_BRIDGE_ShareSet0); I2S_BRIDGE_SetFlexcommSignalShareSet(kI2S_BRIDGE_Flexcomm3, kI2S_BRIDGE_SignalWS, kI2S_BRIDGE_ShareSet0); #if 1 PRINTF("Configure codec\r\n"); /* protocol: i2s * sampleRate: 48K * bitwidth:16 */ if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success) { PRINTF("codec_Init failed!\r\n"); assert(false); } /* Initial volume kept low for hearing safety. * Adjust it to your needs, 0-100, 0 for mute, 100 for maximum volume. */ if (CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight, DEMO_CODEC_VOLUME) != kStatus_Success) { assert(false); } PRINTF("Configure I2S\r\n"); #endif /* * masterSlave = kI2S_MasterSlaveNormalMaster; * mode = kI2S_ModeI2sClassic; * rightLow = false; * leftJust = false; * pdmData = false; * sckPol = false; * wsPol = false; * divider = 1; * oneChannel = false; * dataLength = 16; * frameLength = 32; * position = 0; * watermark = 4; * txEmptyZero = true; * pack48 = false; */ I2S_TxGetDefaultConfig(&s_TxConfig); s_TxConfig.divider = DEMO_I2S_CLOCK_DIVIDER; s_TxConfig.masterSlave = DEMO_I2S_TX_MODE; I2S_TxInit(DEMO_I2S_TX, &s_TxConfig); DMA_Init(DEMO_DMA); DMA_EnableChannel(DEMO_DMA, DEMO_I2S_TX_CHANNEL); DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S_TX_CHANNEL, kDMA_ChannelPriority3); DMA_CreateHandle(&s_DmaTxHandle, DEMO_DMA, DEMO_I2S_TX_CHANNEL); StartSoundPlayback(); while (1) { } } static void StartSoundPlayback(void) { PRINTF("Setup looping playback of sine wave\r\n"); s_TxTransfer.data = &g_Music[0]; s_TxTransfer.dataSize = sizeof(g_Music); I2S_TxTransferCreateHandleDMA(DEMO_I2S_TX, &s_TxHandle, &s_DmaTxHandle, TxCallback, (void *)&s_TxTransfer); /* need to queue two transmit buffers so when the first one * finishes transfer, the other immediatelly starts */ I2S_TxTransferSendDMA(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer); I2S_TxTransferSendDMA(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer); } static void TxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData) { /* Enqueue the same original buffer all over again */ i2s_transfer_t *transfer = (i2s_transfer_t *)userData; I2S_TxTransferSendDMA(base, handle, *transfer); } Audio data buffer:   Figure 7 Audio source sends buffer The corresponding test results are given:   Figure 8 Audio source sending data test It can be seen that the data sent by the audio source is cyclical and can be sent in an increasing loop. 4. Test results There are several points to verify about the test results: (1) 4-channel audio receives pingpong buffer, whether a single buffer is 10ms, that is, a 10ms audio data pool. (2) How long is the data memory copy time, whether it will exceed the length of the receiving audio data pool. (3) Whether the received 4-channel data is synchronized, whether the assembled send buffer data is the 32bit*8ch data assembled from the corresponding 4-channel 2ch data. (4) Whether the sent audio waveform is the correct 32bit*8ch TDM data. The following are the verification test results for these points. 4.1 4 I2S audio 10ms data pool This verification is very simple. Define a pin GPIO, initialize the output to 0, and then reverse it in the received callback interrupt. This article chooses to reverse it in the I2S5 callback. The test results are as follows:   Figure 9 ch1 10ms duration Channel 1 is the exact 10ms because of the callback reversal received. Here is a general picture of the test:   Figure 10 Time test overview Ch1: I2S5 callback entry frequency Ch2: memory copy time Ch3: Send callback entry frequency It can be seen that the frequency of sending and receiving is 10ms, because the sending frequency is also 48Khz, but because it is 8ch, the data volume is 4 times that of receiving, and all the data of the 4 receiving channels need to be stuffed in. 4.2 Time consumption of receiving and copying to sending buffer For data copying, that is, assembling the data received from 4 I2S channels into 4 buffers into the sending buffer, this time test is on the second channel of the oscilloscope, and the results are as follows:   Figure 11 copy data time It can be seen that the copying time is less than 500us, which is much shorter than the 10ms of the audio receiving data pool. Therefore, you can use memcpy casually without worrying about the copying time being too long. This also makes up for the regret that I wanted to use DMA for memory to memory copying before, but it could not be realized due to DMA performance issues. 4.3 Verification of the synchronization of the data received on the 4 I2S In order to verify the synchronization, this article closes the 4 I2S receiving channel after receiving 100times 10ms, and prints out the corresponding 4 I2S audio receiving buffer. The results of the 4 I2S buffer are as follows:   Figure12 I2S2 receive buffer   Figure 13 I2S3 receive buffer   Figure 14 I2S4 receive buffer   Figure 15 I2S5 receive buffer It can be seen that the receive buffer data of the 4 I2S are completely synchronized, and all start from 0XB8.   4.4 Send buffer corresponding to 4-channel audio TDM The send buffer is printed after 100 receptions, and then memcpy is performed to the send buffer, and the printout of the send buffer data is as follows:   Figure 16 I2S1 transfer buffer It can be seen that the buffer also starts from 0XB8, and the 4 groups of received data are copied to the send buffer and assembled into 32bit*8ch data. It can be seen that the TDM send buffer is also correct.   4.5 Sending 48Khz 32bit 8ch audio data waveform   Figure 17 Transmitting and receiving audio waveforms The upper group is the waveform of the audio source, and the lower group is the waveform of TDM transmission. Due to the limitation of the analysis software of the logic analyzer, it can only analyze 2ch 64bit data at most, so only part of the data can be seen here, but from the waveform, it can be seen that the waveform of sending TDM can achieve 32bit*8ch, and every 8byte data in a frame is the same, which also explains the synchronization of 4-channel audio reception. In the above figure, the data of ch2 is actually 00, 01, 02, 03, 04, 05, 06, 07, 4 groups of the same data in one frame, and the waveform can also be seen that there are 4 groups of the same data, and 4 groups of 2ch are enough to form 32bit 8ch TDM. Finally, here is another TDM waveform tested on the oscilloscope:   Figure 18 Sending TDM waveform It can be seen that BCLK=12.28Mhz is consistent with the expected 48khz*32bit*8=12.288Mhz. The WS signal is also measured to be 48Khz, which meets the set 48Khz sampling rate. DATA is also transmitting with data changes, and it can be seen that the waveform pattern within a frame is repeated by about 4 groups, which also shows that the 4 groups of received data are synchronized. So far, the function of RT600 4-channel 48KHZ 32bit*2ch input and assembling into 48Khz 32bit*8ch output has been realized!  
記事全体を表示
i.MXRT1170 crossover MCUs are a new generation product in the RT family of NXP. It has 1 GHz speed and rich on-chip peripherals. Among RT1170 sub-family, RT1173/RT1175/RT1176 have dual core. One cortex-M7 core runs in 1 GHz, and one cortex-M4 core runs in 400 MHz. The two cores can be debugged through one SWD port. In MIMXRT1170-EVK,the Freelink debug interface default use CMSIS-DAP as debug probe. When debug two core project, for example the evkmimxrt1170_hello_world_cm7 project and evkmimxrt1170_hello_world_cm4 project, just click the debug button in CM7 project. After CM7 project become debug status, CM4 project start to debug automatically. But if developer want to use jlink as debug probe, he will find the CM4 project will not start automatically. If he start CM4 project debugging manually, it will fail. Can jlink debug dual core simultaneously? Yes, it can. In order to debug dual core by jlink, there are some additional settings need to be done. IDE and SDK MCUXpresso IDE 11.3, MIMXRT1170-EVK SDK 2.9.1, Jlink probe version 9 or above or change Freelink application firmware to jlink, Segger jlink firmware JLink_Windows_V698a. Import SDK example, here we select multicore_examples/evkmimxrt1170_hello_world_cm7. MCUXpresso IDE can import both CM4 and CM7 project automatically. Compile both project. Debug the CM7 project first. Then switch to CM4 project and also click the debug button. The CM4 project will not debug properly. So, we exit debug. With this step, the IDE created two deug configurations in RUN->Debug Configurations. Click the evkmimxrt1170_hello_world_cm4 JLink Debug, click JLink Debugger label, Add evkmimxrt1170_connect_cm4_cm4side.jlinkscript. Then unselect the “Attach to a running target” checkbox.   Set a breakpoint at start of main() function of the CM4 project. This is because some time the IDE can’t suspend at start of main() when start debugging. A second breakpoint can be helpful. Take care to set the break point on BOARD_ConfigMPU() or below code. Don’t set break point on “gpio_pin_config_t led_config…”. Otherwise, debug will fail. Now we can start to debug CM7 project. Click the debug button in RUN-> evkmimxrt1170_hello_world_cm4 JLink Debug. This is because the IDE will enable “attach to a running target” automatically. We must disable it again. When CM7 debug circumstance is ready, switch to CM4 project and click “debug” button. Then resume the CM7 project. The CM4 project will start debugging and suspend at the breakpoint.   Notes: If you follow this guide but still can’t debug both core, please try to erase whole chip and try again. If CM7 project run fails in MCMGR_INIT(), please check the Boot Configure pin. It should be set to Internal Boot mode.
記事全体を表示
RT1050 HAB Encrypted Image Generation and Analysis 1, Introduction      The NXP RT series can support multiple boot modes, it incluses: unsigned image mode, HAB signed image mode, HAB encryption image mode, and BEE encryption  image mode.       In order to understand the specific structure of the HAB encryption app, this article will generate a non-XIP app image, then generate the relevant burning file through the elftosb.exe tool in the flashloader i.MX-RT1050, and use MFGTOOL to enter the serial download mode to download the .sb file.       This article will focus on the download steps of RT1050 HAB encryption related operations, and analyze the structure of the HAB encrypted app image.     2, RT1050 HAB Encypted Operation Procedure At first, we analyze the steps of MFGtool burning, which files are needed, so as to give specific preparation, open the ucl2.xml file in the following path of the flashloader: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware Because we need to use the HAB encrypated boot mode, then we will use MXRT105X-SecureBoot, from the ucl2.xml file, we will find the following related code: Fig 1. MXRT1050-SecureBoot structure As you can see from the above, to implement the secure boot of RT1050, you need to prepare these three files: ivt_flashlloader_signed.bin: it is the signed flashloader binary file enable_hab.sb: it is used to modify the SRK and HABmode in the fuse map boot_image.sb: HAB encrypted app program file       Here is a flow chart of the overall HAB encryption operation step, after checking this figure, then we will follow it step by step.     Fig 2. MXRT1050 HAB encrypted image flow chart     The app image we used in this article is the RAM app, so, at first, we need to prepare one RAM based app image. In this document, we are directly use the prepared  RAM based app image: evkbimxrt1050_led_softwarereset_0xa000.s19, this app code function is: After download the code to the MIMXRT1050-EVKB(qspi flash) board, the on board led D18 will blinky and printf the information, after pressing the WAKEUP button SW8, the code will implement software reset and printf the related information. The unsigned code test print result are as follows:      BOARD RESET start.  Helloworld. WAKEUP key pressed, will do software system reset.    BOARD RESET start.  Helloworld. 2.1 CST tool preparation      Because the contains a lot of steps, then customer can refer to the following document do the related configuration, this document, we won’t give the CST configuration detail steps. Please check these documents: https://www.cnblogs.com/henjay724/p/10219459.html https://community.nxp.com/docs/DOC-340904 Security Application Note AN12079 After the CST tool configuration, please copy the cst.exe, crts folder, key folder from cst folder to the same folder that holds elftosb executable files: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Please also copy SRK_1_2_3_4_fuse.bin and SRK_1_2_3_4_table.bin to the above folder. 2.2  Sign flashloader    Please refer to application note AN12079 chapter 3.3.1, copy flashloader.elf from folder path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Flashloader And the imx-flexspinor-normal-signed.bd  from folder path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\bd_file\imx10xx to the folder: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Please open commander window under the elftosb folder, then input this commander: elftosb.exe -f imx -V -c imx-flexspinor-flashloader-signed.bd -o ivt_flashloader_signed.bin flashloader.elf   Fig 3.  Sign flashloader  This steps will generate the  ivt_flashlaoder_signed.bin, which is needed to put under the MFGtool OS Firmware folder, just used for enter the signed flashloader mode. 2.3 SRK and HAB mode fuse modification files Please refer to AN12079 chapter 4.3, copy the enable_hab.bd file from folder path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\bd_file\imx10xx to this folder path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Please refer to the chapter 2.1 generated SRK_1_2_3_4_fuse.bin, modify the enable_hab.bd like the following picture: Fig 4. enable_hab.bd SRK and HAB mode fuse modification Then,  in the elftosb window, please input the following command, just used to generate the enable_hab.sb program file: elftosb.exe -f kinetis -V -c enable_hab.bd -o enable_hab.sb   Fig 5. SRK and HAB mode program files generation 2.4 APP Encrypted Image      If you want to do the HAB encrypted image download, you need to prepare one non-XIP app image, here we prepared one RAM based APP srec files.      Because the app file is the RAM files, then we also need the related RAM encrypted .bd files, please copy imx-itcm-encrypted.bd from the folder path:      Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\bd_file\imx10xx to this folder path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Open imx-itcm-encrypted.bd, then modify the following content: options {     flags = 0x0c;     # Note: This is an example address, it can be any non-zero address in ITCM region     startAddress = 0x8000;     ivtOffset = 0x1000;     initialLoadSize = 0x2000;     # Note: This is required if the cst and elftsb are not in the same folder     # Note: This is required if the default entrypoint is not the Reset_Handler     #       Please set the entryPointAddress to Reset_Handler address   entryPointAddress = 0x0000a2dd; } Here, we need to note these two points: (1)    ivtOffset = 0x1000; If the external flash is flexspi flash, then we need to modify ivtOffset as 0X1000, if it is the nandflash, we need to use the 0X400. (2) entryPointAddress = 0x0000a2dd; The entryPointsAddress should be the app code reset handlder, it is the app start address+4 data, the entry address is also OK, but we suggest you to use the app Reset_Handler address. Fig 6. App reset handler address Then input the following commander in the elftosb windows: elftosb.exe -f imx -V -c imx-itcm-encrypted.bd -o ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin evkbimxrt1050_led_softwarereset_0xa000.s19 Fig 7. App HAB Encrypted file generation Please note, we need to record the generated key blob offset address, it is 0XA00, just like the above data in the red frame, this address will be used in the next chapter’s .bd file. After this step, it will generate 7 files:          (1)  ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin, this file includes the FDCB which is filled with 0, IVT, BD, DCD, APP HAB encrypted image data, CSF data (2)  ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted_nopadding.bin, compare with ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin, this file deletes the 0s which is above IVT range. (3)  Csf.bin, it is the HAB data area, you can find the data contains the csf data, it is from 0X8000 to 0X8F80 in the generated ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin. Fig 8. Csf data and the encrypted app relationship      (4) dek.bin Fig 9. Dek data DEK data is the AES-128 bits key, it is not defined by the customer, it is random generated automatically by the HAB encrypted tool. (5) input.csf Open it, you can find the following content: Fig10. Input csf file content (6) rawbytes.bin,  this is the app image plaintext data, it doesn’t contains the FDCB,IVT,BOOTDATA, DCD, csf etc.    (7) temp.bin, it is the temporary file, compare with ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin, no csf files.   2.5 HAB Encrypted QSPI program file    Here we need to prepare one program_flexspinor_image_qspinor_keyblob.bd file, and put it under the same folder as elftosb, this file is used to generate the HAB encrypted program .sb file. Because the flashloader package didn’t contains it, then we paste all the related content, and I will also attach it in the attachment. # The source block assign file name to identifiers sources { myBinFile = extern (0); dekFile = extern (1); } constants { kAbsAddr_Start= 0x60000000; kAbsAddr_Ivt = 0x60001000; kAbsAddr_App = 0x60002000; } # The section block specifies the sequence of boot commands to be written to the SB file section (0) { #1. Prepare Flash option # 0xc0000006 is the tag for Serial NOR parameter selection # bit [31:28] Tag fixed to 0x0C # bit [27:24] Option size fixed to 0 # bit [23:20] Flash type option # 0 - QuadSPI SDR NOR # 1 - QUadSPI DDR NOR # 2 - HyperFLASH 1V8 # 3 - HyperFLASH 3V # 4 - Macronix Octal DDR # 6 - Micron Octal DDR # 8 - Adesto EcoXIP DDR # bit [19:16] Query pads (Pads used for query Flash Parameters) # 0 - 1 # 2 - 4 # 3 - 8 # bit [15:12] CMD pads (Pads used for query Flash Parameters) # 0 - 1 # 2 - 4 # 3 - 8 # bit [11: 08] Quad Mode Entry Setting # 0 - Not Configured, apply to devices: # - With Quad Mode enabled by default or # - Compliant with JESD216A/B or later revision # 1 - Set bit 6 in Status Register 1 # 2 - Set bit 1 in Status Register 2 # 3 - Set bit 7 in Status Register 2 # 4 - Set bit 1 in Status Register 2 by 0x31 command # bit [07: 04] Misc. control field # 3 - Data Order swapped, used for Macronix OctaFLASH devcies only (except MX25UM51345G) # 4 - Second QSPI NOR Pinmux # bit [03: 00] Flash Frequency, device specific load 0xc0000006 > 0x2000; # Configure QSPI NOR FLASH using option a address 0x2000 enable flexspinor 0x2000; #2 Erase flash as needed. erase 0x60000000..0x60020000; #3. Program config block # 0xf000000f is the tag to notify Flashloader to program FlexSPI NOR config block to the start of device load 0xf000000f > 0x3000; # Notify Flashloader to response the option at address 0x3000 enable flexspinor 0x3000; #5. Program image load myBinFile > kAbsAddr_Ivt; #6. Generate KeyBlob and program it to flexspinor # Load DEK to RAM load dekFile > 0x10100; # Construct KeyBlob Option #--------------------------------------------------------------------------- # bit [31:28] tag, fixed to 0x0b # bit [27:24] type, 0 - Update KeyBlob context, 1 Program Keyblob to flexspinor # bit [23:20] keyblob option block size, must equal to 3 if type =0, # reserved if type = 1 # bit [19:08] Reserved # bit [07:04] DEK size, 0-128bit 1-192bit 2-256 bit, only applicable if type=0 # bit [03:00] Firmware Index, only applicable if type = 1 # if type = 0, next words indicate the address that holds dek # the 3rd word #---------------------------------------------------------------------------- # tag = 0x0b, type=0, block size=3, DEK size=128bit load 0xb0300000 > 0x10200; # dek address = 0x10100 load 0x00010100 > 0x10204; # keyblob offset in boot image # Note: this is only an example bd file, the value must be replaced with actual # value in users project load 0x0000a000 > 0x10208; enable flexspinor 0x10200; #7. Program KeyBlob to firmware0 region load 0xb1000000 > 0x10300; enable flexspinor 0x10300; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Please note, in the above chapter, fig 7, we mentioned the keyblob offset address, we need to modify it in the following code:     load 0x0000a000 > 0x10208; Now, combine program_flexspinor_image_qspinor_keyblob.bd, ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted_nopadding.bin and dek.bin file together, we use the following commander to generate the boot_image.sb: elftosb.exe -f kinetis -V -c program_flexspinor_image_qspinor_keyblob.bd -o boot_image.sb ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted_nopadding.bin dek.bin Fig 11. App HAB encrypted program file generation Until now, we will find, all the related HAB encrypted files is prepared. 2.6 MFG Tool program HAB Encrypted files to RT1050-EVKB        Before we program it, please copy the following 3 files which is in the elftosb folder: ivt_flashloader_signed.bin enable_hab.sb boot_image.sb to this folder: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware Please modify cfg.ini, the file path is: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel Modify the content as: [profiles] chip = MXRT105X [platform] board = [LIST] name = MXRT105X-SecureBoot Choose MXRT105X-SecureBoot program mode. Then open the tool MfgTool2.exe, the board MIMXRT1050-EVKB(need to modify the on board resistor, use the qspi flash) mode should be serial download mode, just modify SW7:1-OFF,2-OFF,3-OFF, 4-ON, connect two usb cable between PC and the board J28 and J9. After the connection, you will find the MfgTool2.exe can detect the HID device: Fig 12. MFG tool program After the program is finished, power off the board, modify the boot mode to internal boot, it is SW7:1-OFF,2-OFF,3-ON, 4-OFF,connect the COM terminal, power on the EVKB board, after reset, you will find the D18 led is blinking, after you press the SW8, you will find the following printf information: BOARD RESET start. Helloworld. WAKEUP key pressed, will do software system reset. ? BOARD RESET start. Helloworld.‍‍‍‍‍‍‍‍‍‍‍‍‍ So, the HAB encrypted image works OK now. 3. App HAB encrypted image structure analysis 3.1 MCUBootUtility Configuration to check the RT Encrypted image      Here, we can also use  MCUBootUtility tool to check the RT chip encrypted image and the fuse data.      If the cst is your own configured, please do the following configuration at first:     (1)Copy the configured cst folder to folder: NXP-MCUBootUtility-2.0.0\tools Delete the original cst folder. (2)Copy SRK_1_2_3_4_fuse.bin and SRK_1_2_3_4_table.bin to folder:  NXP-MCUBootUtility-2.0.0\gen\hab_cert Now, you can use the new MCUBootutility to connect your board which already done the HAB encrypted method. 3.1 RT1050 fuse map comparation Before do the HAB encrypted image program, I have read out the whole fuse map as follows: Fig 13. MIMXRT1050-EVKB fuse map before HAB encrypted image Fig 14. MIMXRT1050-EVKB fuse map after HAB encrypted image Compare the fuse map between do the HAB encrypted image and no HAB encrypted image, we can find two difference: HAB mode, 0X460 bit1:0 open, 1 close SRK area We can find, after program the HAB encrypted image, the SRK fuse data is the same as the SRK data which is defined in the enable_hab.bd. 3.2  Readout HAB encrypted QSPI APP image structure analysis From MCUBootUtility tool, we can find the HAB Encypted image structure should be like this: Fig 15. HAB Encrypted image structure What about the real example image case? Now, we use the MCUbootUtility tool to read out our HAB encrypted image, from address 0X60000000, the readout size is 0XB000. The detail image structure is like following:   Fig 16. HAB Encypted image example structure   1): IVT:  hdr,  IVT header, more details, check hab_hdr 2):    IVT: entry, the app entrypointAddress, it should be the reset_handler address, in this document example, it is the address 0xa004 data, the plaintext is 0X00A2DD, but after the HAB encrypted, we can find the address -x60002004 data is the encrypted data 3):  IVT: reserved 4):  IVT: DCD, it is used for the DRAM SEMC configuration, in this example, we didn’t use the SDDRAM, so the data is 0. 5):  IVT: BOOT_DATA, used to indicate the BOOT_DATA  RAM start address 0X9020. 6):  IVT: self, ivt self RAM start address is 0X9000 7):  IVT:CSF, it is used to indicate the CST start address, this example csf ram address is 0X00010000. 8):  IVT:reserved 9): BOOT_DATA:  RAM image start,  the whole image RAM start address, this RAM example BOOT_DATA is 0X8000,0XA000-0X2000=0X8000 10): BOOT_DATA: size, APP file size, it is 0X0000A200, after checking the file generated HAB encrypted app image size, you can find the image end size is really 0XA200, just like the fig 16. 11):  HAB  Encypted app data,  please check ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin file, the address 0X2000-0X7250 data, you will find it is the same.   12): HAB data, it incluses the csf, certificate etc data, you can compare the file ivt_evkbimxrt1050_led_softwarereset_0xa000_encrypted.bin address 0X8000-0x8f70 data, it is the same. 13):DEK blob, it is the DEK key blob related data, the offset address is 0XA000, the same as fig 7. FDCB,IVT,BOOT DATA are all plaintext, but app image area is the HAB encrypted data, HAB and the DEK blob is the generated data put in the related memory. Conclusion     This document we mainly use the elftosb and the MFGTool to generate the HAB encrypted image, and download it to the RT1050 EVKB board, document give the whole detail steps, and us ethe MCUBootutility tool to read out the HAB encrypted image, and analysis the HAB encrypted image structure with the examples.  After compare with the generated mid files, we can find all the data is consist, and all the encrypted data range is the same. The test result also demonstrate the HAB encrypted code function works, the HAB encrypted boot has no problems. All the related files is in the attachment.      
記事全体を表示
In case you missed our recent webinar, you can check out the slides and comment below with any questions.
記事全体を表示
Updating Firmware via USB DFU Based on RT1170 Updating Firmware via USB DFU Based on RT1170         Development Environment         Preparing dfu-util                  Steps to Prepare dfu-util         Running the Demo                  Using Prebuilt Firmware from SDK                  Using Custom Firmware Performing microcontroller (MCU) firmware upgrades in the field without the aid of external programming tools is a necessary feature. For MCUs that support USB device controllers, the USB Device Firmware Update (DFU) class offers a solution. the USB_DFU bootloader requires only a PC and a USB cable. The RT series also provides this feature. In the case of the RT1170, for example, a DFU project is provided in the SDK under the USB class. The project is based on the MCUXpresso IDE. by running the dev_dfu_freertos_cm7 project in the SDK, the RT1170 will be enumerated as a dfu device, and after connecting it to the Host PC via another USB cable, the user can use the “dfu-util” utility to download a firmware to this device. Development Environment Software Environment: SDK Version: 2.15.000 IDE: MCUXpresso IDE Demo Project: dev_dfu_freertos_cm7 Host Software: dfu-util Download link: dfu-util For Windows 64-bit: Download dfu-util-0.9-win64.zip   Hardware Environment: Board: RT1170-EVKB   Preparing dfu-util dfu-util is used to download Firmware to a DFU device, but it does not add CRC32 to the Firmware. Since the DFU demo in the SDK verifies the CRC32 to ensure the Firmware written to Flash is free from bit errors, modifications to the dfu-util source code are necessary. Steps to Prepare dfu-util Install Dependencies sudo apt-get build-dep libusb-1.0-0 dfu-util sudo apt-get install gcc-mingw-w64-x86-64 Download dfu-util and libusb Source Code git clone https://git.code.sf.net/p/dfu-util/dfu-util git clone https://github.com/libusb/libusb.git Modify CRC Code in Source Modify the dfu_store_file function in dfu_file.c to add CRC32 to the Firmware suffix. /* write suffix, if any */ if (write_suffix) {     uint8_t dfusuffix[DFU_SUFFIX_LENGTH];     dfusuffix[0] = file->bcdDevice & 0xff;     dfusuffix[1] = file->bcdDevice >> 8;     dfusuffix[2] = file->idProduct & 0xff;     dfusuffix[3] = file->idProduct >> 8;     dfusuffix[4] = file->idVendor & 0xff;     dfusuffix[5] = file->idVendor >> 8;     dfusuffix[6] = file->bcdDFU & 0xff;     dfusuffix[7] = file->bcdDFU >> 8;     dfusuffix[8] = 'U';     dfusuffix[9] = 'F';     dfusuffix[10] = 'D';     dfusuffix[11] = DFU_SUFFIX_LENGTH;     /*crc = dfu_file_write_crc(f, crc, dfusuffix,     DFU_SUFFIX_LENGTH - 4);*/     dfusuffix[12] = crc;     dfusuffix[13] = crc >> 8;     dfusuffix[14] = crc >> 16;     dfusuffix[15] = crc >> 24;     crc = dfu_file_write_crc(f, crc, dfusuffix +     12, 4); }   Build libusb mkdir -p build cd libusb-1.0.24 ./autogen.sh PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure --host=x86_64-w64-mingw32 --prefix=$PWD/../build make make install cd .. Build dfu-util cd dfu-util-0.11 ./autogen.sh PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure --host=x86_64-w64-mingw32 --prefix=$PWD/../build make make install cd .. After these steps, the newly built tool will be located in the /build/bin folder.   Open cmd for Windows. Run the following command with the new dfu-suffix.exe and CRC32 will be added to the Firmware. dfu-suffix.1 exe -a your_Firmware   Running the Demo Using Prebuilt Firmware from SDK The SDK provides a prebuilt Firmware binary (dev_hid_mouse_bm.bin) that already includes CRC32. Follow these steps: Use MCUXpresso IDE to flash the dev_dfu_freertos_cm7 demo to the EVKB board.     Connect the board to the Host PC via USB.   In the USB Device Descriptor, we find the Vendor ID and Product ID:     Run the following command to download the Firmware: dfu-util.exe -d <your_vid:pid> -D <your_Firmware> After downloading, the DFU demo will verify the CRC32 and execute the new Firmware in RAM. The device will be enumerated as a USB mouse, moving in a rectangular pattern on the screen. Using Custom Firmware When using custom Firmware, ensure that the image is loaded at the correct address (e.g., 0x10000). If the offset is incorrect, the DFU demo will fail to load the Firmware, even if the CRC check passes.   To build and load custom Firmware: Import the hello_world_cm7 project into MCUXpresso IDE. In the Managed Linker Script settings, enable "Link application to RAM".   Adjust memory settings to match the DFU project requirements, ensuring ITCM is the first RAM region.   Build the project and generate a binary file.   Use the modified dfu-util tool to append CRC32 to the binary and download it to the board. Verify that the custom Firmware executes correctly. CRC Added:   New Firmware loaded successfully:   For Chinese version and demo, please check this link:  https://www.nxpic.org.cn/module/forum/forum.php?mod=viewthread&tid=803149&fromuid=3253523
記事全体を表示
As we know, the RT series MCUs support the XIP (Execute in place) mode and benefit from saving the number of pins, serial NOR Flash is most commonly used, as the FlexSPI module can high efficient fetch the code and data from the Serial NOR flash for Cortex-M7 to execute. The fetch way is implementing via utilizing the Quad IO Fast Read command, meanwhile, the serail NOR flash works in the SDR (Single Data transfer Rate) mode, it receives data on SCLK rise edge and transmits data on SCLK fall edge. Comparing to the SDR mode, the DDR (Dual Data transfer Rate) mode has a higher throughput capacity, whether it can provide better performance of XIP mode, and how to do that if we want the Serial NOR Flash to work in DDR (Dual Data transfer Rate) mode? SDR & DDR mode SDR mode: In SDR (Single Data transfer Rate) mode, data is only clocked on one edge of the clock (either the rising or falling edge). This means that for SDR to have data being transmitted at X Mbps, the clock bit rate needs to be 2X Mbps. DDR mode: For DDR (Dual Data transfer Rate) mode, also known as DTR (Dual Transfer Rate) mode, data is transferred on both the rising and falling edge of the clock. This means data is transmitted at X Mbps only requires the clock bit rate to be X Mbps, hence doubling the bandwidth (as Fig 1 shows).   Fig 1 Enable DDR mode The below steps illustrate how to make the i.MX RT1060 boot from the QSPI with working in DDR mode. Note: The board is MIMXRT1060, IDE is MCUXpresso IDE Open a hello_world as the template Modify the FDCB(Flash Device Configuration Block) a)Set the controllerMiscOption parameter to supports DDR read command. b) Set Serial Flash frequency to 60 MHz. c)Parase the DDR read command into command sequence. The following table shows a template command sequence of DDR Quad IO FAST READ instruction and it's almost matching with the FRQDTR (Fast Read Quad IO DTR) Sequence of IS25WP064 (as Fig 2 shows).   Fig2 FRQDTR Sequence d)Adjust the dummy cycles. The dummy cycles should match with the specific serial clock frequency and the default dummy cycles of the FRQDTR sequence command is 6 (as the below table shows).   However, when the serial clock frequency is 60MHz, the dummy cycle should change to 4 (as the below table shows).   So it needs to configure [P6:P3] bits of the Read Register (as the below table shows) via adding the SET READ PARAMETERS command sequence(as Fig 3 shows) in FDCB manually. Fig 3 SET READ PARAMETERS command sequence In further, in DDR mode, the SCLK cycle is double the serial root clock cycle. The operand value should be set as 2N, 2N-1 or 2*N+1 depending on how the dummy cycles defined in the device datasheet. In the end, we can get an adjusted FCDB like below. // Set Dummy Cycles #define FLASH_DUMMY_CYCLES 8 // Set Read register command sequence's Index in LUT table #define CMD_LUT_SEQ_IDX_SET_READ_PARAM 7 // Read,Read Status,Write Enable command sequences' Index in LUT table #define CMD_LUT_SEQ_IDX_READ 0 #define CMD_LUT_SEQ_IDX_READSTATUS 1 #define CMD_LUT_SEQ_IDX_WRITEENABLE 3 const flexspi_nor_config_t qspiflash_config = { .memConfig = { .tag = FLEXSPI_CFG_BLK_TAG, .version = FLEXSPI_CFG_BLK_VERSION, .readSampleClksrc=kFlexSPIReadSampleClk_LoopbackFromDqsPad, .csHoldTime = 3u, .csSetupTime = 3u, // Enable DDR mode .controllerMiscOption = kFlexSpiMiscOffset_DdrModeEnable | kFlexSpiMiscOffset_SafeConfigFreqEnable, .sflashPadType = kSerialFlash_4Pads, //.serialClkFreq = kFlexSpiSerialClk_100MHz, .serialClkFreq = kFlexSpiSerialClk_60MHz, .sflashA1Size = 8u * 1024u * 1024u, // Enable Flash register configuration .configCmdEnable = 1u, .configModeType[0] = kDeviceConfigCmdType_Generic, .configCmdSeqs[0] = { .seqNum = 1, .seqId = CMD_LUT_SEQ_IDX_SET_READ_PARAM, .reserved = 0, }, .lookupTable = { // Read LUTs [4*CMD_LUT_SEQ_IDX_READ] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xED, RADDR_DDR, FLEXSPI_4PAD, 0x18), // The MODE8_DDR subsequence costs 2 cycles that is part of the whole dummy cycles [4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(MODE8_DDR, FLEXSPI_4PAD, 0x00, DUMMY_DDR, FLEXSPI_4PAD, FLASH_DUMMY_CYCLES-2), [4*CMD_LUT_SEQ_IDX_READ + 2] = FLEXSPI_LUT_SEQ(READ_DDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00), // READ STATUS REGISTER [4*CMD_LUT_SEQ_IDX_READSTATUS] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), [4*CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ(STOP, FLEXSPI_1PAD, 0x00, 0, 0, 0), // WRTIE ENABLE [4*CMD_LUT_SEQ_IDX_WRITEENABLE] = FLEXSPI_LUT_SEQ(CMD_SDR,FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x00), // Set Read register [4*CMD_LUT_SEQ_IDX_SET_READ_PARAM] = FLEXSPI_LUT_SEQ(CMD_SDR,FLEXSPI_1PAD, 0x63, WRITE_SDR, FLEXSPI_1PAD, 0x01), [4*CMD_LUT_SEQ_IDX_SET_READ_PARAM + 1] = FLEXSPI_LUT_SEQ(STOP,FLEXSPI_1PAD, 0x00, 0, 0, 0), }, }, .pageSize = 256u, .sectorSize = 4u * 1024u, .blockSize = 64u * 1024u, .isUniformBlockSize = false, }; Is DDR mode real better? According to the RT1060's datasheet, the below table illustrates the maximum frequency of FlexSPI operation, as the MIMXRT1060's onboard QSPI flash is IS25WP064AJBLE, it doesn't contain the MQS pin, it means set MCR0.RXCLKsrc=1 (Internal dummy read strobe and loopbacked from DQS) is the most optimized option. operation mode RXCLKsrc=0 RXCLKsrc=1 RXCLKsrc=3 SDR 60 MHz 133 MHz 166 MHz DDR 30 MHz 66 MHz 166 MHz In another word, QSPI can run up to 133 MHz in SDR mode versus 66 MHz in DDR mode. From the perspective of throughput capacity, they're almost the same. It seems like DDR mode is not a better option for IS25WP064AJBLE and the following experiment will validate the assumption. Experiment mbedtls_benchmark I use the mbedtls_benchmark as the first testing demo and I run the demo under the below conditions: 100MH, SDR mode; 133MHz, SDR mode; 66MHz, DDR mode; According to the corresponding printout information (as below shows), I make a table for comparison and I mark the worst performance of implementation items among the above three conditions, just as Fig 4 shows. SDR Mode run at 100 MHz. FlexSPI clock source is 3, FlexSPI Div is 6, PllPfd2Clk is 720000000 mbedTLS version 2.16.6 fsys=600000000 Using following implementations: SHA: DCP HW accelerated AES: DCP HW accelerated AES GCM: Software implementation DES: Software implementation Asymmetric cryptography: Software implementation MD5 : 18139.63 KB/s, 27.10 cycles/byte SHA-1 : 44495.64 KB/s, 12.52 cycles/byte SHA-256 : 47766.54 KB/s, 11.61 cycles/byte SHA-512 : 2190.11 KB/s, 267.88 cycles/byte 3DES : 1263.01 KB/s, 462.49 cycles/byte DES : 2962.18 KB/s, 196.33 cycles/byte AES-CBC-128 : 52883.94 KB/s, 10.45 cycles/byte AES-GCM-128 : 1755.38 KB/s, 329.33 cycles/byte AES-CCM-128 : 2081.99 KB/s, 279.72 cycles/byte CTR_DRBG (NOPR) : 5897.16 KB/s, 98.15 cycles/byte CTR_DRBG (PR) : 4489.58 KB/s, 129.72 cycles/byte HMAC_DRBG SHA-1 (NOPR) : 1297.53 KB/s, 448.03 cycles/byte HMAC_DRBG SHA-1 (PR) : 1205.51 KB/s, 486.04 cycles/byte HMAC_DRBG SHA-256 (NOPR) : 1786.18 KB/s, 327.70 cycles/byte HMAC_DRBG SHA-256 (PR) : 1779.52 KB/s, 328.93 cycles/byte RSA-1024 : 202.33 public/s RSA-1024 : 7.00 private/s DHE-2048 : 0.40 handshake/s DH-2048 : 0.40 handshake/s ECDSA-secp256r1 : 9.00 sign/s ECDSA-secp256r1 : 4.67 verify/s ECDHE-secp256r1 : 5.00 handshake/s ECDH-secp256r1 : 9.33 handshake/s   DDR Mode run at 66 MHz. FlexSPI clock source is 2, FlexSPI Div is 5, PllPfd2Clk is 396000000 mbedTLS version 2.16.6 fsys=600000000 Using following implementations: SHA: DCP HW accelerated AES: DCP HW accelerated AES GCM: Software implementation DES: Software implementation Asymmetric cryptography: Software implementation MD5 : 16047.13 KB/s, 27.12 cycles/byte SHA-1 : 44504.08 KB/s, 12.54 cycles/byte SHA-256 : 47742.88 KB/s, 11.62 cycles/byte SHA-512 : 2187.57 KB/s, 267.18 cycles/byte 3DES : 1262.66 KB/s, 462.59 cycles/byte DES : 2786.81 KB/s, 196.44 cycles/byte AES-CBC-128 : 52807.92 KB/s, 10.47 cycles/byte AES-GCM-128 : 1311.15 KB/s, 446.53 cycles/byte AES-CCM-128 : 2088.84 KB/s, 281.08 cycles/byte CTR_DRBG (NOPR) : 5966.92 KB/s, 97.55 cycles/byte CTR_DRBG (PR) : 4413.15 KB/s, 130.42 cycles/byte HMAC_DRBG SHA-1 (NOPR) : 1291.64 KB/s, 449.47 cycles/byte HMAC_DRBG SHA-1 (PR) : 1202.41 KB/s, 487.05 cycles/byte HMAC_DRBG SHA-256 (NOPR) : 1748.38 KB/s, 328.16 cycles/byte HMAC_DRBG SHA-256 (PR) : 1691.74 KB/s, 329.78 cycles/byte RSA-1024 : 201.67 public/s RSA-1024 : 7.00 private/s DHE-2048 : 0.40 handshake/s DH-2048 : 0.40 handshake/s ECDSA-secp256r1 : 8.67 sign/s ECDSA-secp256r1 : 4.67 verify/s ECDHE-secp256r1 : 4.67 handshake/s ECDH-secp256r1 : 9.00 handshake/s   Fig 4 Performance comparison We can find that most of the implementation items are achieve the worst performance when QSPI works in DDR mode with 66 MHz. Coremark demo The second demo is running the Coremark demo under the above three conditions and the result is illustrated below. SDR Mode run at 100 MHz. FlexSPI clock source is 3, FlexSPI Div is 6, PLL3 PFD0 is 720000000 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 391889200 Total time (secs): 16.328717 Iterations/Sec : 2449.671999 Iterations : 40000 Compiler version : MCUXpresso IDE v11.3.1 Compiler flags : Optimization most (-O3) Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0x25b5 Correct operation validated. See readme.txt for run and reporting rules. CoreMark 1.0 : 2449.671999 / MCUXpresso IDE v11.3.1 Optimization most (-O3) / STACK   SDR Mode run at 133 MHz. FlexSPI clock source is 3, FlexSPI Div is 4, PLL3 PFD0 is 664615368 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 391888682 Total time (secs): 16.328695 Iterations/Sec : 2449.675237 Iterations : 40000 Compiler version : MCUXpresso IDE v11.3.1 Compiler flags : Optimization most (-O3) Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0x25b5 Correct operation validated. See readme.txt for run and reporting rules. CoreMark 1.0 : 2449.675237 / MCUXpresso IDE v11.3.1 Optimization most (-O3) / STACK   DDR Mode run at 66 MHz. FlexSPI clock source is 2, FlexSPI Div is 5, PLL3 PFD0 is 396000000 2K performance run parameters for coremark. CoreMark Size : 666 Total ticks : 391890772 Total time (secs): 16.328782 Iterations/Sec : 2449.662173 Iterations : 40000 Compiler version : MCUXpresso IDE v11.3.1 Compiler flags : Optimization most (-O3) Memory location : STACK seedcrc : 0xe9f5 [0]crclist : 0xe714 [0]crcmatrix : 0x1fd7 [0]crcstate : 0x8e3a [0]crcfinal : 0x25b5 Correct operation validated. See readme.txt for run and reporting rules. CoreMark 1.0 : 2449.662173 / MCUXpresso IDE v11.3.1 Optimization most (-O3) / STACK   After comparing the CoreMark scores, it gets the lowest CoreMark score when QSPI works in DDR mode with 66 MHz. However, they're actually pretty close. Through the above two testings, we can get the DDR mode maybe not a better option, at least for the i.MX RT10xx series MCU.
記事全体を表示
Introduction NXP i.MXRT106x has two USB2.0 OTG instance. And the RT1060 EVK has both of the USB interface on the board. But the RT1060 SDK only has single USB host example. Although RT1060’s USB host stack support multiple devices, but we still need a USB HUB when user want to connect two device. This article will show you how to make both USB instance as host. RT1060 SDK has single host examples which support multiple devices, like host_hid_mouse_keyboard_bm. But this application don’t use these examples. Instead, MCUXpresso Config Tools is used to build the demo from beginning. The config tool is a very powerful tool which can configure clock, pin and peripherals, especially the USB. In this application demo, it can save 95% coding work. Hardware and software tools RT1060 EVK MCUXpresso 11.4.0 MIMXRT1060 SDK 2.9.1 Step 1 This project will support USB HID mouse and USB CDC. First, create an empty project named MIMXRT1062_usb_host_dual_port. When select SDK components, select “USB host CDC” and “”USB host HID” in Middleware label. IDE will select other necessary component automatically.     After creating the empty project, clock should be configured first. Both of the USB PHY need 480M clock.   Step 2 Next step is to configure USB host in peripheral config tool. Due to the limitation of config tool, only one host instance of the USB component is allowed. In this project, CDC VCOM is added first.   Step 3 After these settings, click “Update Code” in control bar. This will turn all the configurations into code and merge into project. Then click the “copy to clipboard” button. This will copy the host task call function. Paste it in the forever while loop in the project’s main(). Besides that, it also need to add BOARD_InitBootPeripherals() function call in main(). At this point, USB VCOM is ready. The tool will not only copy the file and configure USB, but also create basic implementation framework. If compile and download the project to RT1060 EVK, it can enumerate a USB CDC VCOM device on USB1. If characters are send from CDC device, the project can send it out to DAPLink UART port so that you can see the character on a terminal interface in computer. Step 4 To get USB HID mouse code, it need to create another USB HID project. The workflow is similar to the first project. Here is the screenshot of the USB HID configuration.   Click “Update code”, the HID mouse code will be generated. The config tool generate two files, usb_host_interface_0_hid_mouse.c and usb_host_interface_0_hid_mouse. Copy them to the “source” folder in dual host project.     Step 5 Next step is to modify some USB macro definitions. <usb_host_config.h> #define USB_HOST_CONFIG_EHCI 2 /*means there are two host instance*/ #define USB_HOST_CONFIG_MAX_HOST 2 /*The USB driver can support two ehci*/ #define USB_HOST_CONFIG_HID (1U) /*for mouse*/ Next step is merge usb_host_app.c. The project initialize USB hardware and software in USB_HostApplicationInit(). usb_status_t USB_HostApplicationInit(void) { usb_status_t status; USB_HostClockInit(kUSB_ControllerEhci0); USB_HostClockInit(kUSB_ControllerEhci1); #if ((defined FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT)) SYSMPU_Enable(SYSMPU, 0); #endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */ status = USB_HostInit(kUSB_ControllerEhci0, &g_HostHandle[0], USB_HostEvent); status = USB_HostInit(kUSB_ControllerEhci1, &g_HostHandle[1], USB_HostEvent); /*each usb instance have a g_HostHandle*/ if (status != kStatus_USB_Success) { return status; } else { USB_HostInterface0CicVcomInit(); USB_HostInterface0HidMouseInit(); } USB_HostIsrEnable(); return status; } In USB_HostIsrEnable(), add code to enable USB2 interrupt.   irqNumber = usbHOSTEhciIrq[1]; NVIC_SetPriority((IRQn_Type)irqNumber, USB_HOST_INTERRUPT_PRIORITY); EnableIRQ((IRQn_Type)irqNumber); Then add and modify USB interrupt handler. void USB_OTG1_IRQHandler(void) { USB_HostEhciIsrFunction(g_HostHandle[0]); } void USB_OTG2_IRQHandler(void) { USB_HostEhciIsrFunction(g_HostHandle[1]); } Since both USB instance share the USB stack, When USB event come, all the event will call USB_HostEvent() in usb_host_app.c. HID code should also be merged into this function. static usb_status_t USB_HostEvent(usb_device_handle deviceHandle, usb_host_configuration_handle configurationHandle, uint32_t eventCode) { usb_status_t status1; usb_status_t status2; usb_status_t status = kStatus_USB_Success; /* Used to prevent from multiple processing of one interface; * e.g. when class/subclass/protocol is the same then one interface on a device is processed only by one interface on host */ uint8_t processedInterfaces[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE] = {0}; switch (eventCode & 0x0000FFFFU) { case kUSB_HostEventAttach: status1 = USB_HostInterface0CicVcomEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); status2 = USB_HostInterface0HidMouseEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); if ((status1 == kStatus_USB_NotSupported) && (status2 == kStatus_USB_NotSupported)) { status = kStatus_USB_NotSupported; } break; case kUSB_HostEventNotSupported: usb_echo("Device not supported.\r\n"); break; case kUSB_HostEventEnumerationDone: status1 = USB_HostInterface0CicVcomEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); status2 = USB_HostInterface0HidMouseEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); if ((status1 != kStatus_USB_Success) && (status2 != kStatus_USB_Success)) { status = kStatus_USB_Error; } break; case kUSB_HostEventDetach: status1 = USB_HostInterface0CicVcomEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); status2 = USB_HostInterface0HidMouseEvent(deviceHandle, configurationHandle, eventCode, processedInterfaces); if ((status1 != kStatus_USB_Success) && (status2 != kStatus_USB_Success)) { status = kStatus_USB_Error; } break; case kUSB_HostEventEnumerationFail: usb_echo("Enumeration failed\r\n"); break; default: break; } return status; } USB_HostTasks() is used to deal with all the USB messages in the main loop. At last, HID work should also be added in this function. void USB_HostTasks(void) { USB_HostTaskFn(g_HostHandle[0]); USB_HostTaskFn(g_HostHandle[1]); USB_HostInterface0CicVcomTask(); USB_HostInterface0HidMouseTask(); }   After all these steps, the dual USB function is ready. User can insert USB mouse and USB CDC device into any of the two USB port simultaneously. Conclusion All the RT/LPC/Kinetis devices with two OTG or HOST can support dual USB host. With the help of MCUXpresso Config Tool, it is easy to implement this function.
記事全体を表示
Note: for similar EVKs, see: Using J-Link with MIMXRT1170-EVKB Using J-Link with MIMXRT1060-EVKB or MIMXRT1040-EVK Using J-Link with MIMXRT1060-EVK or MIMXRT1064-EVK This article provides details using a J-Link debug probe with either of these EVKs.  There are two options: the onboard debug circuit can be updated with Segger J-Link firmware, or an external J-Link debug probe can be attached to the EVK.  Using the onboard debug circuit is helpful as no other debug probe is required.  Appnote AN13206 has more details on this, and the comparison of the firmware options for the debug circuit.  This article details the steps to use either J-Link option.   Using external J-Link debug probe Segger offers several J-Link probe options.  To use one of these probes with these EVKs, configure the EVK with these settings: Remove jumpers J6 and J7, to disconnect the SWD signals from the onboard debug circuit.  These jumpers or installed by default. Power the EVK: the default option is connecting the power supply to barrel jack J43, and setting power switch SW5 to On position (3-6).  The green LED D16 next to SW5 will be lit when the EVK is properly powered. Connect the J-Link probe to J1, 20-pin dual-row 0.1" header.   Using onboard debug circuit with J-Link firmware Disconnect any USB cables from the EVK Power the EVK: the default option is connecting the power supply to barrel jack J43, and setting power switch SW5 to On position (3-6).  The green LED D16 next to SW5 will be lit when the EVK is properly powered. Short jumper J22 to force the debug circuit in DFU mode Connect a USB cable to J11, to the on-board debugger Follow Appnote AN13206 to program the J-Link firmware to the EVK Unplug the USB cable at J11 Remove the jumper at J22 Plug the USB cable back in to J11.  Now the on-board debugger should boot as a JLink. Install jumpers J6 and J7, to connect the SWD signals from onboard debug circuit.  These jumpers or installed by default. Note: with the JLink firmware loaded, USB J11 is no longer an option to power the EVK.  Another option is connecting the power supply to barrel jack J43, and setting power switch SW5 to On position (3-6).  For this power option, jumper J38 needs to short 1-2, which is the default setting. 
記事全体を表示
Note: for similar EVKs, see: Using J-Link with MIMXRT1060-EVK or MIMXRT1064-EVK Using J-Link with MIMXRT1170-EVKB Using J-Link with MIMXRT1160-EVK or MIMXRT1170-EVK. This article provides details using a J-Link debug probe with this EVK.  There are two options: the onboard debug circuit can be updated with Segger J-Link firmware, or an external J-Link debug probe can be attached to the EVK.  Using the onboard debug circuit is helpful as no other debug probe is required.  However, the onboard debug circuit will no longer power the EVK when updated with the J-Link firmware.  Appnote AN13206 has more details on this, and the comparison of the firmware options for the debug circuit.  This article details the steps to use either J-Link option.     Using external J-Link debug probe Segger offers several J-Link probe options.  To use one of these probes with these EVKs, configure the EVK with these settings: Remove jumpers J9 and J10, to disconnect the SWD signals from onboard debug circuit.  These jumpers or installed by default. Use default power selection on J40 with pins 5-6 shorted. Connect the J-Link probe to J2, 20-pin dual-row 0.1" header. Power the EVK with one of the power supply options.  Typically USB connector J1 is used to power the board, and provides a UART/USB bridge through the onboard debug circuit.   Using onboard debug circuit with J-Link firmware Follow Appnote AN13206 to program the J-Link firmware to the EVK. Use jumper J12 to change the mode of the onboard debug circuit: Install J12 to force bootloader mode, to update the firmware image Remove J12 to use the onboard debugger Install jumpers J9 and J10, to connect the SWD signals from onboard debug circuit.  These jumpers are installed by default. Plug USB cable to J1.  This provides connection for J-Link debugger and UART/USB bridge.  However, with J-Link firmware, J1 no longer powers the EVK Power the EVK with another source.  Here we will use another USB port.  Move the jumper on J40 to short pins 3-4 (default shorts pins 5-6) Connect a 2nd USB cable to J48 to power the EVK.  The green LED next to J40 will be lit when the EVK is properly powered.  
記事全体を表示
Goal Our goal is to train a model that can take a value, x, and predict its sine, y. In a real-world application, if you needed the sine of x, you could just calculate it directly. However, by training a model to approximate the result, we can demonstrate the basics of machine learning. TensorFlow and Keras TensorFlow is a set of tools for building, training, evaluating, and deploying machine learning models. Originally developed at Google, TensorFlow is now an open-source project built and maintained by thousands of contributors across the world. It is the most popular and widely used framework for machine learning. Most developers interact with TensorFlow via its Python library. TensorFlow does many different things. In this post, we’ll use Keras, TensorFlow’s high-level API that makes it easy to build and train deep learning networks. To enable TensorFlow on mobile and embedded devices, Google developed the TensorFlow Lite framework. It gives these computationally restricted devices the ability to run inference on pre-trained TensorFlow models that were converted to TensorFlow Lite. These converted models cannot be trained any further but can be optimized through techniques like quantization and pruning. Building the Model To building the Model, we should follow the below steps. Obtain a simple dataset. Train a deep learning model. Evaluate the model’s performance. Convert the model to run on-device. Please navigate to the URL in your browser to open the notebook directly in Colab, this notebook is designed to demonstrate the process of creating a TensorFlow model and converting it to use with TensorFlow Lite. Deploy the mode to the RT MCU Hardware Board: MIMXRT1050 EVK Board Fig 1 MIMXRT1050 EVK Board Template demo code: evkbimxrt1050_tensorflow_lite_cifar10 Code /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. Copyright 2018 NXP. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ #include "board.h" #include "pin_mux.h" #include "clock_config.h" #include "fsl_debug_console.h" #include <iostream> #include <string> #include <vector> #include "timer.h" #include "tensorflow/lite/kernels/register.h" #include "tensorflow/lite/model.h" #include "tensorflow/lite/optional_debug_tools.h" #include "tensorflow/lite/string_util.h" #include "Sine_mode.h" int inference_count = 0; // This is a small number so that it's easy to read the logs const int kInferencesPerCycle = 30; const float kXrange = 2.f * 3.14159265359f; #define LOG(x) std::cout void RunInference() { std::unique_ptr<tflite::FlatBufferModel> model; std::unique_ptr<tflite::Interpreter> interpreter; model = tflite::FlatBufferModel::BuildFromBuffer(sine_model_quantized_tflite, sine_model_quantized_tflite_len); if (!model) { LOG(FATAL) << "Failed to load model\r\n"; exit(-1); } model->error_reporter(); tflite::ops::builtin::BuiltinOpResolver resolver; tflite::InterpreterBuilder(*model, resolver)(&interpreter); if (!interpreter) { LOG(FATAL) << "Failed to construct interpreter\r\n"; exit(-1); } float input = interpreter->inputs()[0]; if (interpreter->AllocateTensors() != kTfLiteOk) { LOG(FATAL) << "Failed to allocate tensors!\r\n"; } while(true) { // Calculate an x value to feed into the model. We compare the current // inference_count to the number of inferences per cycle to determine // our position within the range of possible x values the model was // trained on, and use this to calculate a value. float position = static_cast<float>(inference_count) / static_cast<float>(kInferencesPerCycle); float x_val = position * kXrange; float* input_tensor_data = interpreter->typed_tensor<float>(input); *input_tensor_data = x_val; Delay_time(1000); // Run inference, and report any error TfLiteStatus invoke_status = interpreter->Invoke(); if (invoke_status != kTfLiteOk) { LOG(FATAL) << "Failed to invoke tflite!\r\n"; return; } // Read the predicted y value from the model's output tensor float* y_val = interpreter->typed_output_tensor<float>(0); PRINTF("\r\n x_value: %f, y_value: %f \r\n", x_val, y_val[0]); // Increment the inference_counter, and reset it if we have reached // the total number per cycle inference_count += 1; if (inference_count >= kInferencesPerCycle) inference_count = 0; } } /* * @brief Application entry point. */ int main(void) { /* Init board hardware */ BOARD_ConfigMPU(); BOARD_InitPins(); BOARD_InitDEBUG_UARTPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); NVIC_SetPriorityGrouping(3); InitTimer(); std::cout << "The hello_world demo of TensorFlow Lite model\r\n"; RunInference(); std::flush(std::cout); for (;;) {} } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Test result On the MIMXRT1050 EVK Board, we log the input data: x_value and the inferenced output data: y_value via the Serial Port. Fig2 Received data In a while loop function, It will run inference for a progression of x values in the range 0 to 2π and then repeat. Each time it runs, a new x value is calculated, the inference is run, and the data is output. Fig3 Test result In further, we use Excel to display the received data against our actual values as the below figure shows. Fig4 Dot Plot You can see that, for the most part, the dots representing predicted values form a smooth sine curve along the center of the distribution of actual values. In general, Our network has learned to approximate a sine curve.
記事全体を表示
RT1170 SBL ISP download app for remap function 1. Abstract Previously wrote a post about using the official SBL ISP method to download the APP: RT1170 SBL ISP download SDRAM APP Recently, a customer also needs to use RT1170 SBL ISP to download code, but the code app that needs to be downloaded is based on MCUXpresso IDE, which generates a bin file and can be programmed to different locations in the flash, and then use remap to run the corresponding app. Regarding remap, we can know from the SBL documentation that RT1170 can directly support it: Fig 1 Usually, if combined with SFW for SD card, cloud and other app updates, the remap function can be directly supported. Because SFW currently only supports two IDEs: IAR and MDK, and does not support MCUXPresso IDE, it is not particularly convenient for customers to use MCUXPresso to develop apps. Moreover, customers do not need to use an SD card or network cloud to update the code. SBL's ISP Updates are enough. So how to use SBL to implement the remap function of two MCUXpresso apps? For MCUXpresso App, you can use one project, so you only need to modify the content to identify different apps and burn them to different flash addresses. The specific implementation methods and steps are given below. The spatial structure of SBL, APP1, and APP2 codes is as follows: Fig 2 2. SBL operation and modification 2.1 SBL configuration and downloading Refer to the doc chapter 2.1: RT1170 SBL ISP download SDRAM APP Generate the related sbl_iar project. 2.2 SBL add remap code Opern sbl project file: sbl-master\boot\sbl_boot.c int sbl_boot_main(void) code modified like this: int sbl_boot_main(void) { char ch = 0; struct image_header br_hdr1 = { .ih_hdr_size = 0x2000 }; struct boot_rsp rsp = { .br_hdr = &br_hdr1, .br_flash_dev_id = 1, .br_image_off = 0x80000 }; int rc = 0; #ifdef CONFIG_BOOT_SIGNATURE #if defined(SOC_IMXRTYYYY_SERIES) || defined(SOC_LPC55S69_SERIES) CRYPTO_InitHardware(); #endif #endif sbl_flash_init(); #ifdef TEST_FUNCTION enable_image(Permanent_mode); #endif BOOT_LOG_INF("Bootloader Version %s", BOOTLOADER_VERSION); os_heap_init(); BOOT_LOG_INF("remap or not:Y/N\r\n\r\n"); ch = GETCHAR(); BOOT_LOG_INF("input=%c,\r\n\r\n",ch); if((ch == 'Y') || (ch == 'y')) { BOOT_LOG_INF("With remap!\r\n\r\n"); SBL_EnableRemap(BOOT_FLASH_ACT_APP, BOOT_FLASH_ACT_APP+FLASH_AREA_IMAGE_1_SIZE, FLASH_AREA_IMAGE_1_SIZE); } else if((ch == 'N') || ((ch == 'n') )) { BOOT_LOG_INF("Without remap!\r\n\r\n"); SBL_DisableRemap(); } else { BOOT_LOG_INF("Without remap!\r\n\r\n"); } #ifdef SINGLE_IMAGE rc = boot_single_go(&rsp); #else #ifdef SOC_REMAP_ENABLE rc = boot_remap_go(&rsp); #else rc = boot_go(&rsp); #endif #endif /* SINGLE_IMAGE*/ if (rc != 0) { while (1) { BOOT_LOG_ERR("Unable to find bootable image"); SDK_DelayAtLeastUs(3000000, BOARD_BOOTCLOCKRUN_CORE_CLOCK); } } BOOT_LOG_INF("Bootloader chainload address offset: 0x%x", rsp.br_image_off); BOOT_LOG_INF("Reset_Handler address offset: 0x%x", rsp.br_image_off + rsp.br_hdr->ih_hdr_size); BOOT_LOG_INF("Jumping to the image\r\n\r\n"); do_boot(&rsp); BOOT_LOG_ERR("Never should get here"); for (;;); } After modification, build the IAR SBL project, then use the debugger download the sbl to the MIMXRT1170-EVK board. 3. APP prepare Refer to doc chapter 2.2: RT1170 SBL ISP download SDRAM APP In order to know the detail app, we can use the hello_world project, and modify the code like the following: int main(void) { char ch; /* Init board hardware. */ BOARD_ConfigMPU(); BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); PRINTF("hello world1->real addr is 0X30100000\r\n"); //app1 // PRINTF("hello world2->real addr is 0X30200000\r\n");//app2 while (1) { ch = GETCHAR(); PUTCHAR(ch); } } Use app1 printf code, to generate the hello_world1.bin,then add the secure header which match to the SBL, generate the hello_app1.bin. Use app2 printf code, to generate the hello_world2.bin,then add the secure header which match to the SBL, generate the hello_app2.bin. Now, give the details how to generate the related secure app: Open sbl-master\target\evkmimxrt1170\env.bat: Change the path to: cd ..\..\component\secure\mcuboot\scripts copy the mcuxpresso project generated bin file:hello_world1.bin and hello_world2.bin to: sbl-master\component\secure\mcuboot\scripts Use the following commander: python imgtool.py sign --key xxxx_priv.pem --align 4 --version "1.1" --header-size 0x400 --pad-header --slot-size 0x100000 --max-sectors 32 hello_world1.bin hello_app1.bin python imgtool.py sign --key xxxx_priv.pem --align 4 --version "1.1" --header-size 0x400 --pad-header --slot-size 0x100000 --max-sectors 32 hello_world2.bin hello_app2.bin to generate the hello_app1.bin, hello_app2.bin. Fig 3 3. Test result Use the MCUbootutility SBL OTA run mode, after board reset, in 5 seconds to connect the board, then burn: hello_app1.bin to 0X30100000 hello_app2.bin to 0X30200000 Fig 4 Fig 5 After downloading, exit MCUBootutility. Reset the board, in the console wait the log appear, then input ‘Y’ or ‘N’ to select which app boots: ‘Y’: remap, APP2 boot ‘N’: without remap, APP1 boot Test result is:   Fig 6 From the test result, we can see the remap function already works OK.  
記事全体を表示
RT600 MCUXpresso JLINK debug QSPI flash 1 Introduction     MIMXRT600-EVK is the NXP official board, which onboard flash is the external octal flash, the octal flash is connected to the RT685 flexSPI portB. In practical usage, the customer board may use other flash types, eg QSPI flash, and connect to the FlexSPI A port. Recently, nxp published one RT600 customer flash application note: https://www.nxp.com/docs/en/application-note/AN13386.pdf This document mainly gives the CMSIS DAP related flash algorithm usage, which modifies the option data to generate the new flash algo for the different flash types. Some customer’s own board may use the RT600 QSPI flash+MCUXPresso+JLINK to debug the application code. Recently, one of the customers find on his own customer board, when they use debugger JLINK associated with the MCUXPresso download code to the RT600 QSPI flash, they meet download issues, but when using the CMSIS DAP as a debugger and the related QSPI cfx file, they can download OK. So this document mainly gives the experience of how to use the RT600, MCUXpresso IDE, and JLINK to download and debug the code which is located in the external QSPI flash. 2 JLINK driver prepare and test   MCUXpresso IDE use the JLINK download, it will call the JLINK driver related script and the flash algorithm, but to RT600, the JLINK driver will use the RT600 EVK flexSPI port B octal flash in default, so, if the customer board changes to other flexSPI port and to QSPI flash, they need to provide the related QSPI flash algorithm and script file, otherwise, even they can find the ARM CM33 core, the download will be still failed. If customers want to use the MCUXpresso IDE and the JLINK, they need to make sure the JLINK driver attached tool can do the external flash operation, eg, erase, read, write successfully at first. Now, give the JLINK driver related tool how to add the RT600 QSPI flash driver and script file. 2.1 JLINK driver install   Download the Segger JLINK driver from the following link: https://www.segger.com/downloads/jlink/JLink_Windows_V754b_x86_64.exe This document will use the jlink v7.54b to test, other version is similar. Install the driver, the default driver install path is: C:\Program Files\SEGGER 2.2 Universal flashloader RT-UFL    RT-UFL v1.0 is a universal flashloader, which uses one .FLM file for all i.MXRT chips, and the different external flash, it is mainly used for the Segger JLINK debugger. RT-UFL v1.0 downoad link: https://github.com/JayHeng/RT-UFL/archive/refs/tags/v1.0.zip    Now, to the RT600 QSPI, give the related flash algo file patch.    Copy the following path file: \RT-UFL-1.0\algo\SEGGER\JLink_Vxxx To the JLINK install path: \SEGGER\JLink Then copy the content in file: RT-UFL-master\test\SEGGER\JLink_Vxxx\Devices\NXP\iMXRT6xx\archive2\evkmimxrt685.JLinkScript To replace the content in: C:\Program Files\SEGGER\JLink\Devices\NXP\iMXRT_UFL\iMXRT6xx_CortexM33.JLinkScript Otherwise, the MCUXpresso IDE debug reset button function will not work. So, need to add the JLINKScript code for ResetTarget, which will reset the external flash. pic1 The RT-UFL provide 3 types download flash algo: MIMXRT600_UFL_L0, MIMXRT600_UFL_L1, MIMXRT600_UFL_L2. Pic 2 _L0 used for the QSPI Flash and Octal Flash(page size 256 Bytes, sector size 4KB), _L1/2 used for the hyper flash(Page size 512 Bytes,Sector size 4KB/64KB). The JLINKDevices.xml content also can get the detail information. Different name will call different .FLM, the .FLM is the flash algorithm file, the source code can be found in RT-UFL v1.0, it will use different option0 option1 to configure the different external memory when the memory chip can support SFDP. <Device> <ChipInfo Vendor="NXP" Name="MIMXRT600_UFL_L0" WorkRAMAddr="0x00000000" WorkRAMSize="0x00480000" Core="JLINK_CORE_CORTEX_M33" JLinkScriptFile="Devices/NXP/iMXRT_UFL/iMXRT6xx_CortexM33.JLinkScript" Aliases="MIMXRT633S; MIMXRT685S_M33"/> <FlashBankInfo Name="Octal Flash" BaseAddr="0x08000000" MaxSize="0x08000000" Loader="Devices/NXP/iMXRT_UFL/MIMXRT_FLEXSPI_UFL_256B_4KB.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" /> </Device> <!------------------------> <Device> <ChipInfo Vendor="NXP" Name="MIMXRT600_UFL_L1" WorkRAMAddr="0x00000000" WorkRAMSize="0x00480000" Core="JLINK_CORE_CORTEX_M33" JLinkScriptFile="Devices/NXP/iMXRT_UFL/iMXRT6xx_CortexM33.JLinkScript" Aliases="MIMXRT633S; MIMXRT685S_M33"/> <FlashBankInfo Name="Octal Flash" BaseAddr="0x08000000" MaxSize="0x08000000" Loader="Devices/NXP/iMXRT_UFL/MIMXRT_FLEXSPI_UFL_512B_4KB.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" /> </Device> <!------------------------> <Device> <ChipInfo Vendor="NXP" Name="MIMXRT600_UFL_L2" WorkRAMAddr="0x00000000" WorkRAMSize="0x00480000" Core="JLINK_CORE_CORTEX_M33" JLinkScriptFile="Devices/NXP/iMXRT_UFL/iMXRT6xx_CortexM33.JLinkScript" Aliases="MIMXRT633S; MIMXRT685S_M33"/> <FlashBankInfo Name="Octal Flash" BaseAddr="0x08000000" MaxSize="0x08000000" Loader="Devices/NXP/iMXRT_UFL/MIMXRT_FLEXSPI_UFL_512B_64KB.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" /> </Device> 2.3 JLINK commander test Please note, the device need to select as MIMXRT600_UFL_L0 when using the QSPI flash. Pic 3                                         pic 4 Pic 5 We can find, the JLINK command can realize the external QSPI flash read, erase function. 2.4 Jflash Test Operation steps: Target->connect->production programming Pic 6 We can find, the Jflash also can realize the RT600 external QSPI flash erase and program. Please note, not all the JLINK can support JFLASH, this document is using Segger JLINK plus. 3 MCUXpresso configuration and test MCUXpresso: v11.4.0 SDK_2_10_0_EVK-MIMXRT685 MCUXPresso IDE import the SDK project, eg. Helloworld or led_output. 3.1 QSPI FCB configuration    FCB is located from the flash offset address 0X08000400, which is used for the FlexSPI Nor boot configuration, the detailed content of the FCB can be found from the RT600 user manual Table 997. FlexSPI flash configuration block. Different external Flash, the configuration is different, if need to use the QSPI flash, the FCB should use the QSPI related configuration and its own LUT table.    Modify SDK project flash_config folder flash_config.c and flash_config.h, LUT contains fast read, status read, write enable, sector erase, block erase, page program, erase the whole chip. If the external QSPI flash command is different, the LUT command should be modified by following the flash datasheet mentioned related command. const flexspi_nor_config_t flexspi_config = { .memConfig = { .tag = FLASH_CONFIG_BLOCK_TAG, .version = FLASH_CONFIG_BLOCK_VERSION, .readSampleClksrc=kFlexSPIReadSampleClk_LoopbackInternally, .csHoldTime = 3, .csSetupTime = 3, .columnAddressWidth = 0, .deviceModeCfgEnable = 0, .deviceModeType = 0, .waitTimeCfgCommands = 0, .deviceModeSeq = {.seqNum = 0, .seqId = 0,}, .deviceModeArg = 0, .configCmdEnable = 0, .configModeType = {0}, .configCmdSeqs = {0}, .configCmdArgs = {0}, .controllerMiscOption = (0), .deviceType = 1, .sflashPadType = kSerialFlash_4Pads, .serialClkFreq = kFlexSpiSerialClk_133MHz, .lutCustomSeqEnable = 0, .sflashA1Size = BOARD_FLASH_SIZE, .sflashA2Size = 0, .sflashB1Size = 0, .sflashB2Size = 0, .csPadSettingOverride = 0, .sclkPadSettingOverride = 0, .dataPadSettingOverride = 0, .dqsPadSettingOverride = 0, .timeoutInMs = 0, .commandInterval = 0, .busyOffset = 0, .busyBitPolarity = 0, .lookupTable = { #if 0 [0] = 0x08180403, [1] = 0x00002404, [4] = 0x24040405, [12] = 0x00000604, [20] = 0x081804D8, [36] = 0x08180402, [37] = 0x00002080, [44] = 0x00000460, #endif // Fast Read [4*0+0] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), [4*0+1] = FLEXSPI_LUT_SEQ(MODE4_SDR, FLEXSPI_4PAD, 0x00, DUMMY_SDR , FLEXSPI_4PAD, 0x09), [4*0+2] = FLEXSPI_LUT_SEQ(READ_SDR , FLEXSPI_4PAD, 0x04, STOP_EXE , FLEXSPI_1PAD, 0x00), //read status [4*1+0] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04), //write Enable [4*3+0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP_EXE, FLEXSPI_1PAD, 0), // Sector Erase byte LUTs [4*5+0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18), // Block Erase 64Kbyte LUTs [4*8+0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD8, RADDR_SDR, FLEXSPI_1PAD, 0x18), //Page Program - single mode [4*9+0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18), [4*9+1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP_EXE, FLEXSPI_1PAD, 0x0), //Erase whole chip [4*11+0]= FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP_EXE, FLEXSPI_1PAD, 0), }, }, .pageSize = 0x100, .sectorSize = 0x1000, .ipcmdSerialClkFreq = 1, .isUniformBlockSize = 0, .blockSize = 0x10000, }; This code has been tested on the RT685+ QSPI flash MT25QL128ABA1ESE, the code boot is working. 3.2 Debug configuration Configure the JLINK options in the MCUXpresso IDE as the JLINK driver: JLinkGDBServerCL.exe Windows->preferences Pic 7 Press debug, generate .launch file. Pic 8 Run->Debug configurations           Pic 9 Choose the device as MIMXRT600_UFL_L0, if the SWD wire is long and not stable, also can define the speed as the fixed low frequency. 3.3 Download and debug test Before download, need to check the RT685 ISP mode configuration, as this document is using the 4 wire QSPI and connect to the FlexSPI A port, so the ISP boot mode should be FlexSPI boot from Port A: ISP2 PIO1_17 low, ISP1 PIO1_16 high, ISP0 PIO1_15 high Click debug button, we can see the code enter the debug mode, and enter the main function, the code address is located in the flexSPI remap address. Pic 10 Click run, we can find the RT685 pin P0_26 is toggling, and the UART interface also can printf information. The application code is working. 4 External SPI flash operation checking To the customer designed board, normally we will use the JLINK command to check whether it can find the ARM core or not at first, make sure the RT chip can work, then will check the external flash operation or not. 4.1 SDK IAP flash code test We can use the SDK related code to test the external flash operation or not at first, the SDK code path is: SDK_2_10_0_EVK-MIMXRT685\boards\evkmimxrt685\driver_examples\iap\iap_flash Then, check the external flash, and modify the code’s related option0, option1 to match the external flash. About the option 0 and option1 definition, we can find it from the RT600 user manual Table 1004.Option0 definition and Table 1005.Option1 definition Pic 11 Pic 12 To the external QSPI flash which is connected to the FLexSPI portA, we can modify the option to the following code:     option.option0.U = 0xC0000001;//EXAMPLE_NOR_FLASH;     option.option1.U = 0x00000000;//EXAMPLE_NOR_FLASH_OPTION1; Then burn the IAP_flash project to the RT685 internal RAM, debug to run it. Pic 13 We can find, the external QSPI flash initialization, erase, read and write all works, and the memory also can find the correct data. 4.2 MCUBootUtility test   Chip enter the ISP mode, then use the MCUBootUtility tool to connect the RT685 and QSPI flash, to do the application code program and read test. ISP mode:ISP2:high, ISP1: high ISP0 low Configure FlexSPI NOR Device Configuration as QSPI, we can use the template: ISSI_IS25LPxxxA_IS25WPxxxA. Pic 14 Click connect to ROM button, check whether it can recognize the external flash: Pic 15 After connection, we can use the tool attached RT685 image to download: NXP-MCUBootUtility-3.3.1\apps\NXP_MIMXRT685-EVK_Rev.E\led_blinky_0x08001000_fdcb.srec Pic 16 We can find, the connection, erase, program and read are all work, it also indicates the RT685+external QSPI flash is working. Then can go to debug it with IDE and debugger.    
記事全体を表示
  RT1176 has two core. Normally, the CM7 core is the main core. When boot up, CM7 will boot up first. Then it will copy CM4’s image to RAM and kick off CM4 core. The details can be found in AN13264. In RT1176, CM4 has 128K ITCM and 128K DTCM. This space is not big. It is enough for CM4 to do some auxiliary work. But sometimes, customer need CM4 to do more. For example, the CM7 may run an ML algorithm and CM4 to deal with USB/ENET and camera. That need more code space than 128K. In this case, CM4 image should be moved to OCRAM1/2 or SDRAM. OCRAM and SDRAM are both connect to a NIC-301 AXI bus arbiter IP. They have similar performance and character. This article will try to use SDRAM because it is more difficult to move to. Before moving, customer should know an important thing. the R/W speed of CM4 accessing OCRAM/SDRAM is slow. Because the CM4 requests data from SDRAM through XB (LPSR domain - AHB protocol) and then through NIC (WAKEUPMIX domain AXI protocol) and the clock limitation is BUS / BUS_LPSR. If both code and data placed in SDRAM the performance will significantly be reduced. SDRAM is accessible only via SYSTEM bus (so, in such case no harward possible). If any other bus masters are accessing the same memory the performance is even more degraded due to arbitration (on XB or NIC). So, user should arrange the whole memory space very well to eliminate access conflict.   Prepare for the work 1.1 Test environment: • SDK: 2.9.1 for i.MX RT1170 • MCUXpresso: 11.4.0 Example: SDK_root\boards\evkmimxrt1170\multicore_examples\hello_world. Set hardware and software Set the board to XIP boot mode by setting SW1 to OFF OFF ON OFF. Import the hello_world example from SDK. Build the project.   Moving to SDRAM for debug option In CM7 project, add SDRAM space in properties->MCU settings->Memory detail   Then in properties->settings->Multicore, change the CM4 master memory region to SDRAM.   Unlike other IDE, MCUXpresso can wake up M4 project thread and download M4 image by IDE itself. it calls implicit. This field tell IDE where to place CM4 image. In properties->settings->Preprocessor, add XIP_BOOT_HEADER_DCD_ENABLE. This is to add DCD to image's head. DCD can be used to program the SDRAM controller for optimal settings, improving the boot performance. Next, switch to CM4 project. Add SDRAM space to memory table, just like what we do in CM7 project.     In properties-> Managed Linker Script, it’s better to announce Heap and stack space in DTCM. It also can be placed in SDRAM, but this should be careful. After that, we can start debugging. You can see that the SDRAM has been filled with CM4 image. Click Resume button, the CM4 project will stop at the beginning of the Main.   Moving to SDRAM for release option To compile the project in release mode, CORE1_IMAGE_COPY_TO_RAM should be added to Defined symbols table. But that is not enough. The CM7 project of SDK doesn’t copy the CM4 image. We must add this to CM7 project. 3.1 Create a new file named incbin.S. This is the code .section .core_m4slave , "ax" @progbits @preinit_array .global dsp_text_image_start .type dsp_text_image_start, %object .align 2 dsp_text_image_start: .incbin "evkmimxrt1170_hello_world_cm4.bin" .global dsp_text_image_end .type dsp_text_image_end, %object dsp_text_image_end: .global dsp_data_image_start .type dsp_data_image_start, %object .align 2 dsp_ncache_image_end: .global dsp_text_image_size .type dsp_text_image_size, %object .align 2 dsp_text_image_size: .int dsp_text_image_end - dsp_text_image_start 3.2 In hello_world_core0.c, add these code #ifdef CORE1_IMAGE_COPY_TO_RAM extern const char dsp_text_image_start[]; extern int dsp_text_image_size; #define CORE1_IMAGE_START ((uint32_t *)dsp_text_image_start) #define CORE1_IMAGE_SIZE ((int32_t)dsp_text_image_size) #endif 3.3 Right click the evkmimxrt1170_hello_world_cm4.axf in Project Explorer window, select Binary Utilities->Create Binary. A binary file called evkmimxrt1170_hello_world_cm4.bin will be created. Copy it to the release folder of CM7 project. If you want this work to be done automatically, you can add the command to properties->settings->Build stepes->Post-build steps   Compile the project and download. Press reset button. After a while, you will see a small led blinking. This led is driven by CM4. Debug the CM4 project on SDRAM only As we know that CM4 can debug alone without CM7 starting. But that is in ITCM and DTCM. Can it also work in SDRAM. Yes, but the original debug script file is not support this function. I attached a new script file. It can initialize SDRAM before downloading CM4 code. Replace the old .scp file with this one, nothing else need to be changed.
記事全体を表示
1. Abstract     When the customer uses the NXP RT board to debug the code, sometimes, the board   suddenly meets debug connect issues when using the IDE and the debugger to download the code. Especially to the customer who is using the NXP RT EVK board with the onboard default CMSIS-DAP debugger. They even suspect the board is broken after trying a lot of times.     The debugger connects issues that normally happen when using the wrong FDCB, the download process is ended abnormally, the wrong flash loader, or the abnormal app code in the flash, .etc.     The reported issue result will be similar to the following pictures: Fig.1 Fig.2     The connect log maybe:       No connection to chip’s debug port       Error: Wire Ack Wait Fault     This document will give some methods to recover the board when meeting the debugger issues with the typical MIMXRT1060-EVK board +MCUXpresso IDE as the test platform. Other platform is also similar, the recovery method also can be used. 2. RT board recovery method     The main method is to change the RT board to the serial download mode, bring the core to a known state, then do the mass erase in IDE or with the MCUXpresso Secure Provisioning Tool(SPT).     First, let the board enter the serial download mode: Fig.3     Enter serial download mode:     1) SW7: 1-OFF,2-OFF,3-OFF,4-ON     2) Power off and power on again, or Press Reset button 2.1 IDE Mass Erase     MCUXpresso IDE, choose the related debugger interface, then choose “erase flash action”.     Here take the MIMXRT1060-EVK on board default debugger CMSIS DAP as an example: Fig.4 Fig.5    After this operation, when the Board is back to the internal boot again, the debugger can download to the flash again. 2.2 SPT Mass Erase     Customers also can use the NXP MCUXpresso Secure Provisioning Tool to do the code download or the mass erase in the serial download mode, this method also can recover the board, in fact, just let the core in the known status.     SPT tool download link: https://www.nxp.com/design/software/development-software/mcuxpresso-secure-provisioning-tool:MCUXPRESSO-SECURE-PROVISIONING     After installing the SPT tool, open it.     1) Create one RT1060 workspace Fig.6     2) Connect the board with USB or the UART     Here, take USB interface as an example. Fig.7 Fig. 8 Fig.9 Fig.10 Fig.11       Until now, the external flash is erased!     In the SPT, the customer also can double check the memory, especially whether the FDCB area is erased or not, just like in the following picture: Fig.12     The customer can go back to the internal boot mode and use the debugger to download the code again.       Internal boot mode:           SW7:1-OFF,2-OFF,3-ON,4-OFF      Press reset or power off and power on again to enter the internal boot mode, then use the debugger to test it again, this is the result: Fig.13     We can see, the MIMXRT1060-EVK debugger interface is recovered! 3. Conclusion     When the flash contains an app that is abnormal(access memory does not exist, memory is corrupted, misconfiguration of the clocks, etc.), it will cause the board to end up in an unknown state, then the debugger can’t take control over the core. But, when put the core in serial downloader mode, then it will put the core in a known state, this way, the debugger will be able to take control of the core.     So, when meeting the debugger issues in the RT board, try to mass erase the external flash in serial download mode, then it will recover the board debugger to a normal situation.
記事全体を表示
Note: for similar EVKs, see: Using J-Link with MIMXRT1060-EVKB or MIMXRT1040-EVK Using J-Link with MIMXRT1060-EVK or MIMXRT1064-EVK Using J-Link with MIMXRT1160-EVK or MIMXRT1170-EVK This article provides details using a J-Link debug probe with this EVK.  There are two options: the onboard MCU-Link debug probe can be updated with Segger J-Link firmware, or an external J-Link debug probe can be attached to the EVK.  Using the onboard debug circuit is helpful as no other debug probe is required.  This article details the steps to use either J-Link option. MIMXRT1170-EVKB jumper locations   Using external J-Link debug probe Segger offers several J-Link probe options.  To use one of these probes with these EVKs, configure the EVK with these settings: Install a jumper on JP5, to disconnect the SWD signals from the onboard debug circuit.  This jumper is open by default. Power the EVK: the default option is connecting the power supply to barrel jack J43, and setting power switch SW5 to On position (3-6).  The green LED D16 next to SW5 will be lit when the EVK is properly powered. Connect the J-Link probe to J1, 20-pin dual-row 0.1" header.   Using onboard MCU-Link with J-Link firmware Install the MCU-Link Installer for the drivers and firmware update tool Disconnect any USB cables from the EVK Power the EVK: the default option is connecting the power supply to barrel jack J43, and setting power switch SW5 to On position (3-6).  The green LED D16 next to SW5 will be lit when the EVK is properly powered. Install a jumper at JP3 to force the MCU-Link in ISP mode Connect a USB cable to J86, to the MCU-Link debugger Go to the scripts directory in the MCU-Link software package installation and run the program_JLINK.cmd (Windows) or program_JLINK (Linux/MacOS) script by double-clicking it. Follow the onscreen instructions.  In Windows, this script is typically installed at C:\nxp\MCU-LINK_installer_3.122\scripts\program_JLINK.cmd Unplug the USB cable at J86 Remove the jumper at JP3 Plug the USB cable back in to J86.  Now the MCU-Link debugger should boot as a JLink. Remove jumper JP5, to connect the SWD signals from the MCU-Link debugger.  This jumper is open by default.  
記事全体を表示
i.MX RT6xx The RT6xx is a crossover MCU family is a breakthrough product combining the best of MCU and DSP functionality for ultra-low power secure Machine Learning (ML) / Artificial Intelligence (AI) edge processing, performance-intensive far-field voice and immersive 3D audio playback applications. Fig 1 is the block diagram for the i.MX RT600. It consists of a Cortex-M33 core that runs up to 300 MHz with 32KB FlexSPI cache and an optional HiFi4 DSP that runs up to 600MHz with 96KB DSP cache and 128KB DSP TCM. It also contains a cryptography engine and DSP/Math accelerator in the PowerQuad co-processor. The device has 4.5MB on-chip SRAM. Key features include the rich audio peripherals, the high-speed USB with PHY and the advanced on-chip security. There is a Flexcomm peripheral that supports the configuration of numerous UARTs, SPI, I2C, I2S, etc. Fig 1 Create a eIQ (TensorFlow Lite library) demo In the latest version of SDK for the i.MX RT600, it still doesn't contain the demos about the Machine Learning (ML) / Artificial Intelligence (AI), so it needs the developers to create this kind of demo by themself. To implement it, port the eIQ demos cross from i.MX RT1050/1060 to i.MX RT685 is the quickest way. The below presents the steps of creating a eIQ (TensorFlow Lite library) demo. Greate a new C++ project Install SDK library Fig 2 Create a new C++ project using installed SDK Part In the MCUXpresso IDE User Guide, Chapter 5 Creating New Projects using installed SDK Part Support presents how to create a new project, please refer to it for details Porting tensorflow-lite Copy the tensorflow-lite library to the target project Copy the TensorFlow-lite library corresponding files to the target project Fig 3 Add the paths for the above files Fig 4 Fig 5 Fig 6 Porting main code The main() code is from the post: The “Hello World” of TensorFlow Lite Testing On the MIMXRT685 EVK Board (Fig 7), we record the input data: x_value and the inferenced output data: y_value via the Serial Port (Fig 8). Fig 7 Fig 8 In addition, we use Excel to display the received data against our actual values as the below figure shows. Fig 9 In general, In general, it has replicated the result of the The “Hello World” of TensorFlow Lite Troubleshoot In default, the created project doesn't support print float, so it needs to enable this feature by adding below symbols (Fig 10). Fig 10 When a neural network is executed, the results of one layer are fed into subsequent operations and so must be kept around for some time. The lifetimes of these activation layers vary depending on their position in the graph, and the memory size needed for each is controlled by the shape of the array that a layer writes out. These variations mean that it’s necessary to calculate a plan over time to fit all these temporary buffers into as small an area of memory as possible. Currently, this is done when the model is first loaded by the interpreter, so if the area is not big enough, you’ll see a crash event happen. Regard to this application demo, the default heap size is 4 KB, obviously, it's not big enough to store the model’s input, output, and intermediate tensors, as the codes will be stuck at hard-fault interrupt function (Fig 11). Fig 11 So, how large should we allocate the heap area? That’s a good question. Unfortunately, there’s not a simple answer. Different model architectures have different sizes and numbers of input, output, and intermediate tensors, so it’s difficult to know how much memory we’ll need. The number doesn’t need to be exact—we can reserve more memory than we need—but since microcontrollers have limited RAM, we should keep it as small as possible so there’s space for the rest of our program. We can do this through trial and error. For this application demo, the code works well after increasing ten times than the previous heap size (Fig 12). Fig 12
記事全体を表示
This article will help you understand in detail the necessary steps to connect an external SRAM memory to the RT devices with the SEMC module. This document is focused on RT1170 however a lot of this information can also be followed for other RT devices with the SEMC module, please consult limitations on the specific device Reference Manual. In this post, there is attached an example of this, since the EVK does not contain an SRAM a specific memory is not used for this. This is a theoretical approach to how to set this kind of memory. The user needs to set specific parameters for the memory to be used.   The SEMC is a multi-standard memory controller optimized for both high performance and low pin count. It can support multiple external memories in the same application with shared address and data pins. The interface supported includes SDRAM, NOR Flash, SRAM, and NAND Flash, as well as the 8080 display interface. Features The SEMC includes the following features: SRAM interface Supports SRAM and Pseudo SRAM Supports 8/16 bit modes Supports ADMUX, AADM, and Non-ADMUX modes Up to 4 Chip Select (CS) Up to 4096Mb memory size NOTE For 16-bit devices, up to 4096Mb memory size For 8-bit devices, up to 2048Mb memory size For more detailed features on supported memories of this module please consult Reference Manual How to set SRAM It is important to mention that RT1170 supports ASYNC and SYNC mode on the SRAM however SYNC mode is not supported in all RT devices, e.g. RT1050 does not support SRAM SYNC mode. It is important to consider the pin mux for these devices, for this you can refer to table 29-7 for the RT1170. Please consider that pins controlled through the IOCR register should be static. This means that if you configure, for example, SEMC_ADDR08 to be CE on the SRAM it cannot be used in the same application as A8 in an SDRAM. Let´s go step by step on how to configure the parameters and where to find that information:   Configure MCR[DQSMD] bit to select the read clock source for synchronous mode. Suggest setting it with 0x1 to reach high clock frequency. config.dqsMode = kSEMC_Loopbackdqspad; Configure the IOCR register to choose CS pins. For this, you can refer to table 29-6. I suggest using CSX pins for CS signals of the SRAM. The Init function from the SDK sets this register incorrectly so write this register outside the function SEMC->IOCR |= 0x00908BB6; // A8:CE#0, CSX0:A24, CSX1:A25, CSX2:CE#1, RDY:CE#2 Optional Configure BMCR registers for bus access efficiency, the arbitration adopts a weight-based algorithm where the weights are obtained from BMCR registers. A score is calculated and the command with the highest score is served first. The score is calculated with the following formula: SCORE = QOS*WQOS + AGE*WAGE/4 + WSH + WRWS Where : - QOS stands for AxQOS of AXI bus-WQOS is the weight factor of QOS. -AGE stands for the wait period for each command -WAGE is the weight factor of AGE. -WSH stands for the weight of slave hit without read/write switch scenario. -WRWS stands for the weight of the slave hit with read/write switch scenario. This is used when you have multiple devices connected to the module and you want to assign access priorities to the different devices.   Configure Base Register 6/9/10/11 with base address, memory size, and valid information. BRx[BA]: In this field, you set the address where the SRAM is going to be located. You can refer to the specific device memory map. In the example, I used 0x9000_0000 but you can use any SEMC location as long it does not overlap with other memory spaces. BRx[MS]: Here you specify the size of the SRAM. [Image from register] BRx[VLD] must be 1 so the memory can be accessed. //VLD is always set to 1 in the SRAM Init function of the SDK sram_config.address = SRAM_BASE;// Base address 0x90000000 (BR6[BA]) sram_config.memsize_kbytes = 0x10000;// SRAM0 space size 64MB (BR6[MS])   Configure INTEN and INTR registers if need to generate interrupts. You can use the function "SEMC_EnableInterrupts()" Configure SRAM Control Register with parameters obtained from the specific SRAM device. These registers contain the timings for the memory used. These values are obtained from the memory datasheet. sram_config.addrPortWidth = 8;// Port width (SRAMCR0[COL])Don't care in SRAM. sram_config.advActivePolarity = kSEMC_AdvActiveLow;//ADV# polarity //(SRAMCR0[ADVP])Don't care if not use ADV. sram_config.addrMode = kSEMC_AddrDataNonMux;//Non Mux mode(SRAMCR0[AM]) sram_config.burstLen = kSEMC_Nor_BurstLen1;//Burst length (SRAMCR0[BL]) sram_config.portSize = kSEMC_PortSize16Bit;//Port size 16bit (SRAMCR0[PS]) sram_config.syncMode = kSEMC_AsyncMode;// ASYNC mode (SRAMCR0[SYNCEN]) sram_config.waitEnable = true;// WAIT enable (SRAMCR0[WAITEN]) sram_config.waitSample = 0;// WAIT sample (SRAMCR0[WAITSP]) sram_config.advLevelCtrl = kSEMC_AdvHigh;// ADV# level control(SRAMCR0[ADVH]) //Don't care if not use ADV. sram_config.tCeSetup_Ns = 20;//CE#setup time[nsec](SRAMCR1[CES])Need tuning. sram_config.tCeHold_Ns = 20;// CE#hold time [nsec](SRAMCR1[CEH]) Need tuning. sram_config.tCeInterval_Ns = 20;//CE#interval time[nsec](SRAMCR2[CEITV]) Need //tuning. sram_config.readHoldTime_Ns = 20;//Read hold time[nsec](SRAMCR2[RDH])Only for //SYNC mode. sram_config.tAddrSetup_N s= 20;//ADDRsetup time[nsec](SRAMCR1[AS])Need tuning. sram_config.tAddrHold_Ns = 20;//ADDRhold time[nsec](SRAMCR1[AH]) Need tuning. sram_config.tWeLow_Ns = 20;//WE low time [nsec] (SRAMCR1[WEL]) Need tuning. sram_config.tWeHigh_Ns = 20;//WE high time [nsec] (SRAMCR1[WEH]) Need tuning. sram_config.tReLow_Ns = 20;// RE low time [nsec] (SRAMCR1[REL]) Need tuning. sram_config.tReHigh_Ns = 20;// RE high time[nsec](SRAMCR1[REH]) Need tuning. sram_config.tTurnAround_Ns = 20;//Turnaround time[nsec](SRAMCR2[TA])Need //tuning but don't set it to be 0. sram_config.tAddr2WriteHold_Ns = 20;//Address to write data hold time [nsec] (SRAMCR2[AWDH]) Need tuning. sram_config.tWriteSetup_Ns = 20;//Write Data setup time[nsec](SRAMCR2[WDS]) //Only for SYNC mode. sram_config.tWriteHold_Ns= 20;//Write Data hold time [nsec] (SRAMCR2[WDH]) //Only for SYNC mode. sram_config.latencyCount = 20;//Latency count[nsec](SRAMCR2[LC]) Only for //SYNC mode. sram_config.readCycle = 20;// read time[nsec](SRAMCR2[RD])Only for SYNC mode. sram_config.delayChain = 20;// typically not used in SRAM. (DCCR [SRAMXVAL], //DCCR [SRAMXEN], DCCR [SRAM0VAL], DCCR [SRAM0EN]) ​ These values are for reference and do not suggest the exact values for a specific SRAM. Initialize the SRAM device by IP command registers (IPCR0/1/2, IPCMD, and IPTXDAT) if needed.  Notes: -Configure independent timing for SRAM device 0 and device 1/2/3 -Configure SRAM device 0 timing with register SRAMCR0~SRAMCR3 -Configure SRAM decive1/2/3 timing with register SRAMCR4~SRAMCR6
記事全体を表示
RT1050 SDRAM app code boot from SDcard burn with 3 tools Abstract       This document is about the RT series app running on the external SDRAM, but boot from SD card. The content contains SDRAM app code generate with the RT1050 SDK MCUXpresso IDE project, burn the code to the external SD card with flashloader MFG tool, and MCUXPresso Secure Provisioning. The MCUBootUtility method can be found from this post: https://community.nxp.com/docs/DOC-346194       Software and Hardware platform: SDK 2.7.0_EVKB-IMXRT1050 MCUXpresso IDE MXRT1050_GA MCUBootUtility MCUXPresso Secure Provisioning MIMXRT1050-EVKB 2 RT1050 SDRAM app image generation     Porting SDK_2.7.0_EVKB-IMXRT1050 iled_blinky project to the MCUXPresso IDE, to generate the code which is located in SDRAM, the configuration is modified like the following items:       2.1 Copy code to RAM 2.2  Modify memory location to SDRAM address 0X80002000 The code which boots from SD card and running in the SDRAM is the non-xip code, so the IVT offset is 0X400, in our test, we put the image from the SDRAM memory address 0x800002000, the configuration is: 2.3 Modify the symbol 2.4 Generate the .s19 file      After build has no problems, then generate the app.s19 file:   Rename the app.19 image file to evkbimxrt1050_iled_blinky_sdram_0x2000.s19, and copy it to the flashloader folder: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win   3, Flashloader configuration and download    This chapter will use flashloader to configure the image which can download the SDRAM app code to the external SD card with MFGTool.       We need to prepare the following files: SDRAM interface configuration file CFG_DCD.bin imx-sdram-unsigned-dcd.bd program_sdcard_image.bd 3.1 SDRAM DCD file preparation      MIMXRT1050-EVKB on board SDRAM is IS42S16160J, we can use the attached dcd_model\ISSI_IS42S16160J\dcd.cfg and dcdgen.exe tool to generate the CFG_DCD.bin, the commander is: dcdgen -inputfile=dcd.cfg -bout -cout   Copy CFG_DCD.bin file to the flashloader path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win 3.2 imx-sdram-unsigned-dcd.bd file Prepare the imx-sdram-unsigned-dcd.bd file content as: options {     flags = 0x00;     startAddress = 0x80000000;     ivtOffset = 0x400;     initialLoadSize = 0x2000;     DCDFilePath = "CFG_DCD.bin";     # Note: This is required if the default entrypoint is not the Reset_Handler     #       Please set the entryPointAddress to Reset_Handler address     entryPointAddress = 0x800022f1; }   sources {     elfFile = extern(0); }   section (0) { }  The above entrypointAddress data is from the .s19 reset handler(0X80002000+4 address data): Copy imx-sdram-unsigned-dcd.bd file to flashloader path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Open cmd, run the following command: elftosb.exe -f imx -V -c imx-sdram-unsigned-dcd.bd -o ivt_evkbimxrt1050_iled_blinky_sdram_0x2000.bin evkbimxrt1050_iled_blinky_sdram_0x2000.s19 After running the command, two app IVT files will be generated: 3.3 program_sdcard_image.bd file Prepare the program_sdcard_image.bd file content as: # The source block assign file name to identifiers sources {  myBootImageFile = extern (0); }   # The section block specifies the sequence of boot commands to be written to the SB file section (0) {       #1. Prepare SDCard option block     load 0xd0000000 > 0x100;     load 0x00000000 > 0x104;       #2. Configure SDCard     enable sdcard 0x100;       #3. Erase blocks as needed.     erase sdcard 0x400..0x14000;       #4. Program SDCard Image     load sdcard myBootImageFile > 0x400;         #5. Program Efuse for optimal read performance (optional)     # Note: It is just a template, please program the actual Fuse required in the application     # and remove the # to enable the command     #load fuse 0x00000000 > 0x07;   } Copy program_sdcard_image.bd to the flashloader path: Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\elftosb\win Open cmd, run the following command: elftosb.exe -f kinetis -V -c program_sdcard_image.bd -o boot_image.sb ivt_evkbimxrt1050_iled_blinky_sdram_0x2000_nopadding.bin Copy the generated boot_image.sb file to the following flashloader path: \Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware 3.4 MFGTool burn code to SD card    Prepare one SD card, insert it to J20, let the board enter the serial download mode, SW7:1-ON 2-OFF 3-OFF 4-ON. Find two USB cable, one is connected to J28, another is connected to J9, we use the HID to download the image.    Open MFGTool.exe, and click the start button:          Modify the boot mode to internal boot, and boot from the external SD card, SW7:1-ON 2-OFF 3-ON 4-OFF.      Power off and power on the board again, you will find the onboard LED D18 is blinking, it means the external SDRAM APP code is boot from external SD card successfully. 4, MCUBootUtility configuration and code download    Please check this community document: https://community.nxp.com/docs/DOC-346194     Here just give one image readout memory map, it will be useful to understand the image location information:     After download, we can readout the SD card image, from 0X400 is the IVT, BD, DCD data, from 0X1000 is the image which is the same as the app.s19 file.     5, MCUXpresso Secure Provisioning configuration and download   This software is released in the NXP official website, it is also the GUI version, which can realize the normal code and the secure code downloading, it will be more easy to use than the flashloader tool, customer don’t need to input the command, the tool help the customer to do it, the function is similar to the MCUBootUtility, MCUBootUtility tool is the opensource tool which is shared in the github, but is not released in the NXP official website.   Now, we use the new official realized tool to download the SDRAM app code to the external SD card, the board still need to enter the serial download mode, just like the flashloader and the MCUBootUtility too, the detail operation is:  We can find this tool is also very easy to use, customer still need to provide the app.19 and the dcd.bin, then give the related boot device configuration is OK.    After the code is downloaded successfully, modify the boot mode to internal boot, and boot from the external SD card, SW7:1-ON 2-OFF 3-ON 4-OFF.     Power off and power on the board again, you will find the onboard LED D18 is blinking, it means the external SDRAM APP code is boot from external SD card successfully.   Until now, all the three methods to download the SDRAM app code to the SD card is working, flashloader is the command based tool, MCUBootUtility and MCUXPresso Secure Provisioning is the GUI tool, which is more easy to use.        
記事全体を表示
 This article provides a generic introduction related to the cryptographical algorithms and HW acceleration. By using i.MX RT117x with related hands-on examples, it aims at helping NXP customers to quickly understand how to use and make a well decision regarding the selection of cryptographic algorithms to use in their products and systems. Note: TL, DR. If the reader has the basic knowledge of the cryptography, please skip to chapter 3. A cryptographic accelerator is a co-processor designed specifically to perform computationally intensive cryptographic operations, there are different names from different chip manufactures. For NXP, ‘CASPER’ on LPC55xx series, but ‘DCP’ or ‘CAAM’ for i.MX and i.MX RT. i.MX RT Name Features i.MXRT10xx   DCP (Data Co-Processor) Symmetric Engines: AES-128 Hash Engines: SHA-1, SHA-256   i.MXRT11xx CAAM  (Cryptographic Acceleration and Assurance Module) Symmetric Engines: AES 128, 192, 256; 3DES, DES; PKHA: RSA, ECDSA,DH,ECDH  Hash Engines: SHA-1, SHA-2, MD5, HMAC Random Number Generation It shows cryptographic features and benchmark performance with 2 examples: Features: CAAM usage in mbedTLS. Performance: Benchmark of HW acceleration or software only   CAAM Features Key Function APIs JobRing0 kCAAM_Sha256 kCAAM_HmacSha1/sha224/384/512 kCAAM_Aes_cbc-128/192/256 RunShaExamples(base,&caamHandle); RunHmacExamples(base,&caamHandle); RunAesCbcExamples(base,&caamHandle); JobRing1 kCAAM_Aes_gcm RunAesGcmExamples(base,&caamHandle); JobRing2 kCAAM_Aes_cbc RunAesCbcExamples(base,&caamHandle); JobRing3 kCAAM_Aes_gcm kCAAM_RNG kCAAM_Red-Block kCAAM_Black-Block kCAAM_CRC RunAesGcmExamples(base,&caamHandle); RunRngExample(base, &caamHandle); RedBlobExample(base, &caamHandle); BlackBlobExample(base, &caamHandle); RunCrcExamples(base, &caamHandle);   Key words: Cryptography, Cryptographic HW Acceleration, i.MX RT   
記事全体を表示