Kinetis Microcontrollers Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Kinetis Microcontrollers Knowledge Base

Discussions

Sort by:
OpenSDA/OpenSDAv2 is a serial and debug adapter that is built into several Freescale evaluation boards. It provides a bridge between your computer (or other USB host) and the embedded target processor, which can be used for debugging, flash programming, and serial communication, all over a simple USB cable.   The OpenSDA hardware consists of a circuit featuring a Freescale Kinetis K20 microcontroller (MCU) with an integrated USB controller. On the software side, it implements a mass storage device bootloader which offers a quick and easy way to load OpenSDA applications such as flash programmers, run-control debug interfaces, serial to USB converters, and more. Details on OpenSDA can be found in the OpenSDA User Guide.     The bootloader and app firmware that lay on top of the original OpenSDA circuit was proprietary.  But recently ARM decided to open source their CMSIS-DAP interface, and now a truly open debug platform could be created. This new open-sourced firmware solution is known as OpenSDAv2.   OpenSDAv2: OpenSDAv2 uses the exact same hardware circuit as the original OpenSDA solution, and out of the box it still provides a debugger, drag-and-drop flash programmer, and virtual serial port over a single USB cable.   The difference is the firmware implementation: OpenSDA: Programmed with the proprietary P&E Micro developed bootloader. P&E Micro is the default debug interface app. OpenSDAv2: Programmed with the open-sourced CMSIS-DAP/mbed bootloader. CMSIS-DAP is the default debug interface app.       Firmware Developer Kinetis K20 Based Hardware Circuit Default Debug Interface Drag-and-drop Target MCU Flash Programming Virtual Serial Port Source Code Available OpenSDA P&E Micro x P&E Micro .srec/.s19 x   OpenSDAv2 ARM/mbed.org x CMSIS-DAP .bin x x   The bootloader and app firmware used by OpenSDAv2 is developed by the community at mbed.org, and is known as “CMSIS-DAP Interface Firmware”. If you explore that site, you will find that this firmware was also ported to run on other hardware, but the combination of this mbed.org firmware with the Kinetis K20 MCU is known as OpenSDAv2.   It is important to understand however that it is possible to run a P&E Micro debug app on the CMSIS-DAP/mbed bootloader found on OpenSDAv2. Likewise it is possible to run a CMSIS-DAP debug app on the P&E Micro bootloader found on OpenSDA. The debug application used needs to be targeted towards a specific bootloader though, as a single binary cannot be used on both the OpenSDA and OpenSDAv2 bootloaders.   OpenSDAv2.1: During development of OpenSDAv2 features and bug fixes, it was found that the reserved bootloader space was too small. Thus a new version of OpenSDAv2 had to be created, which was named OpenSDAv2.1. The difference between the OpenSDAv2.0 and v2.1 is the address where the debug application starts: for OpenSDAv2.0 it expects the application at address 0x5000, while OpenSDAv2.1 expects the application to start at address 0x8000.   The only board with OpenSDAv2.0 is the FRDM-K64F. All other OpenSDAv2 boards (such as the just released FRDM-K22F) use OpenSDAv2.1.   Unfortunately this means that new OpenSDAv2 apps are needed. From a user perspective this mostly affects the JLink app since it was shared across all boards. Make sure you download the correct app for your board based on the OpenSDAv2 version.   OpenSDAv2 Apps: mbed CMSIS-DAP for FRDM-K64F mbed CMSIS-DAP for FRDM-K22F P&E Micro  (use the Firmware Apps link) Segger JLink (look at bottom of page for OpenSDAv2.0 or OpenSDAv2.1 app)   OpenSDAv2 Bootloader: The key difference between OpenSDA and OpenSDAv2 is the bootloader. Boards with OpenSDA use a proprietary bootloader developed by P&E Micro, and it cannot be erased or reprogrammed by an external debugger due to the security restrictions in the firmware. Boards with OpenSDAv2 use the open-source bootloader developed by mbed.org, and it can be erased and reprogrammed with an external debugger.   Apps need to be specifically created to work with either the P&E bootloader (Original OpenSDA) or the CMSIS-DAP/mbed bootloader (OpenSDAv2/OpenSDAv2.1) as the bootloader memory map is different.  Thus it’s important to know which type of bootloader is on your board to determine which version of an app to load.   You can determine the bootloader version by holding the reset button while plugging in a USB cable into the OpenSDA USB port. A BOOTLOADER drive will appear for both OpenSDA and OpenSDAv2.   The OpenSDAv2.0 bootloader (may also be called the CMSIS-DAP/mbed bootloader) developed by mbed.org will have the following files inside.  Viewing the HTML source of the bootload.htm file with Notepad will tell you the build version, date, and git hash commit. For the OpenSDAv2.1 bootloader, this file will be named mbed.htm instead.     The OpenSDAv1 bootloader developed by P&E Micro will have the following inside. Clicking on SDA_INFO.HTM will take you to the P&E website.       Using CMSIS-DAP: When you connect a Freedom board that has OpenSDAv2 (such as the FRDM-K64F) to your computer with a USB cable, it will begin running the default CMSIS_DAP/mbed application which has three main features.   1. Drag and Drop MSD Flash Programming You will see a new disk drive appear labeled “MBED”.   You can then drag-and-drop binary (.bin) files onto the virtual hard disk to program the internal flash of the target MCU.   2.Virtual Serial Port OpenSDAv2 will also enumerate as a virtual serial port, which you can use a terminal program , such as TeraTerm (shown below), to connect to. You may need to install the mbed Windows serial port driver first before the serial port will enumerate on Windows properly. It should work without a driver for MacOS and Linux.   3. Debugging The CMSIS-DAP app also allows you to debug the target MCU via the CMSIS-DAP interface. Select the CMSIS-DAP interface in your IDE of choice, and inside the CMSIS-DAP options select the Single Wire Debug (SWD) option:   Kinetis Design Studio (KDS): Note: OpenOCD with CMSIS-DAP for FRDM-K22F is not supported in KDS V1.1.0. You must use either the P&E app instructions or the JLink app instructions to use KDS with the FRDM-K22F at this time. This will be fixed over the next few weeks. OpenSDAv2 uses the OpenOCD debug interface which uses the CMSIS-DAP protocol. Make sure '-f kinetis.cfg' is specified as 'Other Options':   IAR     Keil:         Resources CMSIS-DAP Interface Firmware mbed.org FRDM-K64 Page FRDM-K64 User Guide OpenSDAv2 on MCU on Eclipse blog OpenSDA User Guide KDS Debugging   Appendix A: Building the CMSIS-DAP Debug Application The open source CMSIS-DAP Interface Firmware app is the default app used on boards with OpenSDAv2. It provides: Debugging via the CMSIS-DAP interface Drag-and-drop flash programming Virtual Serial Port providing USB-to-Serial convertor   While binaries of this app are provided for supported boards, some developers would like to build the CMSIS-DAP debug application themselves.   This debug application can be built for either the OpenSDAv2/mbed bootloader, or for the original OpenSDA bootloader developed by P&E Micro. If you are not sure which bootloader your board has, refer to the bootloader section in this document.   Building the CMSIS-DAP debug application requires Keil MDK. You will also need to have the “Legacy Support for Cortex-M Devices” software pack installed for Keil.   You will also need Python 2.x installed. Due to the python script used, Python 3.x will not work.   The code is found in the MBED git repository, so it can be downloaded using a git clone command: “git clone https://github.com/mbedmicro/CMSIS-DAP.git” Note that there is a Download Zip option, but you will run into a issue when trying to compile that version, so you must download it via git instead.   The source code can be seen below:   This repository contains the files for both the bootloader and the CMSIS-DAP debug interface application. We will concentrate on the interface application at the moment.   Open up Keil MDK, and open up the project file located at \CMSIS-DAP\interface\mdk\k20dx128\k20dx128_interface.uvproj In the project configuration drop-down box, you will notice there are a lot of options. Since different chips may have slightly different flash programming algorithms, there is a target for each specific evaluation board. In this case, we will be building for the FRDM-K64F board. Scroll down until you get to that selection:   Notice there are three options for the K64: k20dx128_k64f_if: Used for debugging the CMSIS-DAP application with Keil. Code starts at address 0x0000_0000 k20dx128_k64_if_openSDA_bootloader: Creates a binary to drag-and-drop on the P&E developed bootloader (Original OpenSDA) k20dx128_k64_if_mbed_bootloader: Creates a binary to drag-and-drop onto the CMSIS-DAP/mbed developed bootloader (OpenSDAv2)   Since the FRDM-K64F comes with the OpenSDAv2 bootloader, we will use the 3 rd option. If we were building the mbed app for another Freedom board which had the original OpenSDA bootloader, we would choose the 2 nd option instead.   Now click on the compile icon. You may get some errors If you get an error similar to the one shown below, make sure you have installed the Legacy pack for ARM as previously described earlier:           compiling RTX_Config.c...             ..\..\Common\src\RTX_Config.c(184): error:  #5: cannot open source input file "RTX_lib.c": No such file or directory            and           compiling usb_config.c...             ..\..\..\shared\USBStack\INC\usb_lib.c(18): error:  #5: cannot open source input file "..\..\RL\USB\INC\usb.h": No such file or directory   If you get an error regarding a missing version_git.h file, make sure that Python 2.x and git are in your path. A Python build script fetches that file. It's called from the User tab in the project options, under "Run User Programs Before Build/Rebuild". If there is a warning about “invalid syntax” when running the Python script, make sure your using Python 2.x. Python 3.x will not work with the build script.   Now recompile again, and it should successfully compile. If you look now in \CMSIS-DAP\interface\mdk\k20dx128 you will see a new k20dx128_k64f_if_mbed.bin file   If you compiled the project for the OpenSDA bootloader, there would be a new k20dx128_k64f_if_openSDA.S19 file instead.   Loading the CMSIS-DAP Debug Application: Now take the Freedom board, press and hold the reset button as you plug in the USB cable. Then, drag-and-drop the .bin file (for OpenSDAv2) or .S19 file (for OpenSDA) into the BOOTLOADER drive that enumerated.   Perform a power cycle, and you should see a drive called “MBED” come up and you can start using the CMSIS-DAP debug interface, as well as drag-and-drop programming and virtual serial port as described earlier in this document.   Appendix B: Building the CMSIS-DAP Bootloader All Freedom boards already come with a bootloader pre-flashed onto the K20.  But for those building their own boards that would like to use CMSIS-DAP, or those who would like to tinker with the bootloader, it possible to flash it to the Kinetis K20 device. Flashing the bootloader will require an external debugger, such as the Keil ULink programmer or Segger JLink.   Also note that the OpenSDA/PE Micro Bootloader cannot be erased! Due to the proprietary nature of the P&E firmware used by the original OpenSDA, it can only be programmed at the board manufacturer and JTAG is disabled. So these instructions are applicable for boards with OpenSDAv2 only.   First, open up the bootloader project which is located at \CMSIS-DAP\bootloader\mdk\k20dx128\k20dx128_bootloader.uvproj   There is only one target available because all OpenSDAv2 boards will use the same bootloader firmware as the hardware circuitry is the same.   Click on the compile icon and it should compile successfully. If you see errors about a missing version_git.h file, note that Python 2.x must be in the path to run a pre-build script which fetches that file.   Now connect a Keil ULink to J10 and then insert a USB cable to provide power to J26. Note that if you have the 20-pin connector, you’ll want to use the first 10 pins.   Then for Keil 5 you will need to change some debug options (CMSIS-DAP is built under Keil 4.x).   Right click on the bootloader project, and go to the Debug tab and next to ULINK Pro Cortex Debugger, click on Settings:   Then under “Cortex-M Target Driver Setup”, change the “Connect” drop down box to “under Reset” and “Reset” dropdown box to “HW RESET”. Hit OK to save the settings.     Then in Keil, click on Flash->Erase.   And then on Flash->Download.   If you get an “Invalid ROM Table” error when flashing the CMSIS-DAP bootloader, make sure you made the changes to the debugger settings listed above.   After some text scrolls by, you should see:   Now power cycle while holding down the reset button, and you should see the bootloader drive come up. You’ll then need to drag and drop the mbed application built earlier onto it. And that’s all there is to it!   The binaries for the bootloader and CMSIS-DAP debug app for the FRDM-K64F board created in writing this guide are attached. Original Attachment has been moved to: k20dx128_bootloader.axf.zip Original Attachment has been moved to: k20dx128_k64f_mbed.bin.zip
View full article
It has been reported that OpenSDA v2/2.1 bootloader could be corrupted when the board is plugged into a Windows 10 machine. An updated OpenSDA bootloader that fixes this issue is available at www.NXP.com/openSDA. There is also a blog article by Arm addressing this issue. To reprogram the bootloader on affected boards, you will require an external debugger, such as Segger JLink or Keil ULink programmer attached to the JTAG port connected to the K20 OpenSDA MCU. For your convenience, the binaries of the OpenSDA v2.2 bootloader is attached at the bottom of this post. If using a Segger JLink, download the latest JLink Software and Documentation pack and use the following JLink.exe commands to connect to the K20 OpenSDA MCU: Connect MK20DX128xxx5 S 4000 And then use the following commands to reflash the bootloader: erase loadbin <your Bootloader Binary> 0x00000000 Here is another post on how to recover bricked OpenSDA boards and to prevent it getting re-bricked. To check more information regarding OpenSDA on your boards, please go to www.nxp.com/opensda.
View full article
The FlexIO module was first introduced in the Freescale Kinetis KL43 family. It is capable of emulating various serial communication protocols including: UART, SPI and I2C. The FlexIO module is very flexible and you can configure it according to your communication needs. The main components of the FlexIO module are the shifters, timers, and pins. Data is loaded onto a shifter and a timer is assigned to generate the shifter clock and use a pin to output the data from the shifter. The KL43 FlexIO module has 4 32-bit shifters, 4 16-bit timers and 8 bidirectional I/O pins. Each shifter and timer has its own configuration registers. The most important registers that configure the whole FlexIO behavior are the SHIFTCFG, SHIFTCTL, TIMCFG, TIMCTL and TIMCMP registers. There are other registers that contain status flags, interrupt enabling bits and the buffers for the shifters. Shifters have a timer assigned to them to generate the shift clock and it can be configured to shift data in or out. When the shifter is configured to transmit mode, the data from the SHIFTBUF register will be loaded to the shifter and the shifter status flag will be set meaning that the shifter is ready to start the transmission. In receive mode, the shifter status flag is set when SHIFTBUF has been loaded with the data from the shifter, and the status flag is cleared when the SHITBUF register is read. The timers are highly configurable, they can use external or internal triggers to generate certain conditions to reset, enable and disable the timer. The triggers can be a timer output, shifter status flag, pin input or an external trigger input. They can be configured to enable in response to a trigger, pin or shifter condition. Each shifter or timer can be configured to use any FlexIO pin with either polarity. The pins can be used as an input or output. A pin configured as an input for a timer can be used to receive a clock and use it as the shifter clock that is assigned to this timer. Once everything is configured you need to read/write the shifter buffers and the shifter and timer status flags to start a transmission or to read the contents of the shifter buffer when receiving data. The following diagram gives a high-level overview of the configuration of FlexIO timers and shifters. Figure 1. FlexIO block diagram In the following example configuration, the FlexIO module will be configured as a transmitter. It will use one shifter, two timers, and three pins. The pins will be used for the outputs of the shifter and the two timers. One timer will be used as the shifter clock and the other timer will be used as a chip select to show when a transmission is being made. The FlexIO will be configured to have a baud rate of FlexIO clock/4 and will do an 8-bit transmission. Figure 2. Example transmission Timer 0 Timer Configuration 0 Register (FLEXIO_TIMCFG0) = 0x00002200 TIMOUT = 0    Timer output is logic one when enabled and is not affected by timer reset. TIMDEC = 0    Decrement counter on FlexIO clock, Shift clock equals Timer output. TIMRST = 0    Timer never reset. TIMDIS = 2    Timer disabled on Timer compare. TIMENA = 2    Timer enabled on Trigger high. TSTOP  = 0    Stop bit is disabled. TSTART = 0    Start bit disabled. Timer Control 0 Register (FLEXIO_TIMCTL0) = 0x01C30101 TRGSEL = 1    Trigger select. Shifter 0 status flag. TRGPOL = 1    Trigger active low. TRGSRC = 1    Internal trigger selected. PINCFG = 3    Timer pin output. PINSEL = 1    Timer pin 1 select. PINPOL = 0    Pin is active high. TIMOD  = 1    Dual 8-bit counters baud/bit mode. Timer Compare 0 Register (FLEXIO_TIMCMP0) = 0x00000F01 TIMCMP = 0x00000F01        Configure 8-bit transfer with a baud rate of FlexIO clock/4. Set TIMCMP[15:8] = (number of bits x 2) - 1. Set TIMCMP[7:0] = (baud rate divider / 2) - 1. In our case we want an 8-bit transfer so TIMCMP[15:8] = 0xF and a baud rate divider of 4 so TIMCMP[7:0] = 0x1. Timer 1 Timer Configuration 1 Register (FLEXIO_TIMCFG1) = 0x00001100 TIMOUT = 0    Timer output is logic one when enabled and is not affected by timer reset. TIMDEC = 0    Decrement counter on FlexIO clock, Shift clock equals Timer output. TIMRST = 0    Timer never reset. TIMDIS = 1    Timer disabled on Timer N-1 disable. TIMENA = 1    Timer enabled on Timer N-1 enable. TSTOP  = 0    Stop bit is disabled. TSTART = 0    Start bit disabled. Timer Control 1 Register (FLEXIO_TIMCTL1) = 0x00030283 TRGSEL = 0    Trigger select. Doesn’t matter because we won’t use a trigger. TRGPOL = 0    Trigger active high. TRGSRC = 0    External trigger selected. PINCFG = 3    Timer pin output. PINSEL = 2    Timer pin 2 select. PINPOL = 1    Pin is active low. TIMOD  = 3    Single 16-bit counter mode. Timer Compare 1 Register (FLEXIO_TIMCMP1) = 0x0000FFFF TIMCMP = 0x0000FFFF Never compare. Shifter 0 Shifter Control 0 Register (FLEXIO_SHIFTCTL0) TIMSEL = 0    Timer 0 select. TIMPOL = 0    Shift on posedge of Shift clock. PINCFG = 3    Shifter pin output. PINSEL = 0    Shifter pin 0 select. PINPOL = 0    Pin is active high. SMOD   = 2    Transmit mode. Load SHIFTBUF contents into the Shifter on expiration of the Timer. Shifter Configuration 0 Register (FLEXIO_SHIFTCFG0) INSRC  = 0    The input source of the shifter is from a pin. In our cause this doesn’t matter because our shifter is set as transmit mode. SSTOP  = 0    Stop bit disabled. SSTART = 0    Start bit disabled. Once all the FlexIO components are configured you have to enable the FlexIO instance by setting the FLEXEN bit in the FLEX_CTRL register. Initially, the shifter status flag is set and is cleared each time the SHIFTBUF register is written. This flag is set each time the SHIFTBUF data has been transferred to the Shifter (SHIFTBUF is empty).  The shifter status flag 0 is configured to be the trigger of the timer 0, so as soon as the status flag is cleared, the timer 0 will be enabled because TIMENA = 2 (Timer enabled on Trigger high)and TRGPOL = 1 (Trigger active low). The shifter will begin to shift out the data on the positive edge of the clock (TIMPOL = 0) until the timer is disabled. The timer will disable when the timer counter reaches 0 (TIMDIS = 2). The timer 1 is configured to be active (low) when the timer 0 is enabled. This is because TIMDIS = 1 and TIMENA = 1. The compare register is configured to 16-bit counter and set to 0xFFFF. With this value the timer will never compare and always be active when the timer is enabled. To send data, you have to make sure that the previous transaction was completed and you can check this by reading the TIMSTAT flag. This flag sets each time the timer counter reaches 0. Once the TIMSTAT flag is set, you clear it and write your new data to the SHITBUF register to start the transaction. The KSDK 1.2.0 has drivers and a HAL to facilitate the configuration of the FlexIO module. Some of the important functions are: FLEXIO_DRV_Init(uint32_t instance, const flexio_user_config_t *userConfigPtr); Use this function to initialize the FlexIO module before using it. In this configuration you can change the settings in the FLEXIO_CTRL register such as: Doze Enable, Debug Enable, Fast Access and software reset. FLEXIO_HAL_ConfigureTimer(FLEXIO_Type * base, uint32_t timerIdx, const flexio_timer_config_t *timerConfigPtr); Use this function to configure a timer in the FlexIO. This function uses a configuration structure that can change the TIMCFG, TIMCTL and TIMCPM registers. FLEXIO_HAL_ConfigureShifter(FLEXIO_Type * base, uint32_t shifterIdx, const flexio_shifter_config_t *shifterConfigPtr); Use this function to configure a shifter in the FlexIO. This function uses a configuration structure that can change the SHIFTCFG and SHIFTCTL registers. FLEXIO_HAL_SetShifterBuffer(FLEXIO_Type * base, uint32_t shifterIdx, uint32_t value); Use this function to start a transmission. When writing to the SHIFTBUF register, the Shifter Status Flag is cleared. FLEXIO_DRV_Start(uint32_t instance); Use this function to enable the FlexIO module by setting the FLEXEN bit in the FLEX_CTRL register. FLEXIO_HAL_GetTimerStatusFlags(FLEXIO_Type * base); This function returns the contents of the TIMSTAT register. You can use this function to check when a transmission is finished. FLEXIO_HAL_ClearTimerStatusFlags(FLEXIO_Type * base, uint32_t mask); This function clears a specific Timer Status Flag. You can use this function to clear a flag after you read that the flag was set. To change the frequency of the transmission you have to change the value of the TIMCMP register. In dual 8-bit counters baud/bit mode, the lower 8-bits configures the baud rate divider equal to (CMP[7:0] + 1) * 2 and the upper 8-bits configure the number of bits in each word equal to (CMP[15:8] + 1) / 2. In our example the baud rate divider is set to 4, this means CMP[7:0] has the value 1. The number of bits transmitted is set to 8, this means CMP[15:8] has the value 0xF. Let’s change the baud rate divider to 32. To obtain the CMP[7:0] value, we will have to solve the simple equation: 32 = (CMP[7:0]+1)*2 CMP[7:0] = 15=0xF Now let’s change the number of bits to 16. The CMP[15:8] value is defined by: 16 = ((CMP[15:8]+1))/2 CMP[15:8] = 31=0x1F The value for the TIMCMP for the timer 0 has to be 0x00001F0F to get a baud rate divider of 32 and a word length of 16 bits. The waveform will look as follows. Figure 3. 16-bit transmission By default the shifter in the FlexIO transmits the LSB first. To change the transmission order, you have to write to the SHIFTBUFBIS (Bit swapped) register instead of the SHIFTBUF register. There are also other buffer registers: SHIFTBUFBYS and SHIFTBUFBBS. The first register swaps the bytes and the second register swaps the bytes and bits at the same time. When using one of these registers you have to be careful to consider that the length of the SHIFTBUF registers is of 32 bits, so if you choose to use the SHIFTBUFBIS for a transmission and your transmission length is not of 32 bits, you have to start writing your data starting from the most significant bit. The following image shows a MSB transmission. The value 0x6AED0000 was written to the SHIFTBUFBIS register. Figure 4. MSB 16-bit transmission The FlexIO module supports automatic start and stop bit handling. All you have to do is change the SHIFTCFG and the TIMCFG configuration bits. In the SHIFTCFG register set SSTOP to 11 if you want the stop bit to have the value 1, and set the SSTART to 10 if you want the stop bit to have the value 0. In the TIMCFG register set the TSART to 1 and the TSOP to 10. The transmission will look as the following image. Data transmitted 0x0F. Figure 5. Transmission with start and stop bit Changing the phase of the clock is very easy, you just have to set the TIMPOL bit to 1 in the SHIFTCTL register. Figure 6. Shift on negedge of Shift clock The conditions to disable and enable the timers can be configured by changing the TIMENA and TIMDIS values in the TIMCFG register. In our example the timer is enabled by the trigger high. The trigger can be set to be an external pin, a shifter status flag, or a timer output. In our case the trigger was set to the shifter status flag, but you can change this configuration to your communication needs. The timer can also be enabled when the previous timer is enabled, on a certain pin edge, or with a combination of pins and triggers. The timer in the example above disables on the timer compare. This means that when the timer counter reaches zero, the timer will disable automatically. The timer counter is loaded with the timer compare value every time it reaches zero or when it is first enabled.  The timer can also be disabled by other conditions such as: when the previous timer is disabled, on a trigger falling edge, on a pin edge, or on a combination of these. Each pin can be configured to be active high or low. When a pin polarity is changed it only affects the output of the pin, for example, if a timer is set to be the shifter clock and you change the pin polarity, the shifter clock will not change its polarity, only the output to the pin from the timer will change. The configuration for the polarity of the pins is located in the TIMCTL and SHIFTCTL. When the PINPOL value is changed to 1, the pin is active low. In the following image the polarity of the timer pin and the shifter pin was changed to 1, so they are active low. Figure 7. Timer and Shifter active low The FlexIO module can generate an interrupt from 3 sources: Shifter error, Shifter status flag and Timer status flag. To enable the interrupts you need to set the bits in the SHIFTSIEN,SHIFTEIEN and TIMIEN. If you are using KSDK you can enable the interrupt in NVIC by setting true .useInt in the FlexIO user config that the function FLEXIO_DRV_Init utilizes. The default handler for the interruption is named UART2_FLEXIO_IRQHandler. The following example configuration will configure the FlexIO module as a receiver. This configuration works with the first example configuration shown. Both tower boards (TWR-KL43Z48M) have to be connected as shown further below in the Table 1 Hardware connnections. The FlexIO module will use one Shifter, one timer, and three pins. The pins will be used for the input of the shifter, the input clock for the timer and the trigger for the timer. The timer will use pin 1 as an input and its output will be the same as the input clock. The trigger for the timer will be the transmitter chip select pin and it will be used to enable or disable the timer. The FlexIO will be configured to do an 8-bit transmission. Shifter 0 Shifter Control 0 Register (FLEXIO_SHIFTCTL0) = 0x00800001 TIMSEL = 0    Timer 0 select. TIMPOL = 1    Shift on negedge of Shift clock. PINCFG = 0    Shifter pin output disabled. PINSEL = 0    Shifter pin 0 select. PINPOL = 0    Pin is active high. SMOD   = 1    Receive mode. Captures the current Shifter content into the SHIFTBUF on expiration of the Timer. Shifter Configuration 0 Register (FLEXIO_SHIFTCFG0) = 0x00000000 INSRC  = 0    The input source of the shifter is from a pin. In our cause this doesn’t matter because our shifter is set as transmit mode. SSTOP  = 0    Stop bit disabled. SSTART = 0    Start bit disabled. Timer 0 Timer Configuration 0 Register (FLEXIO_TIMCFG0) = 0x01206602 TIMOUT = 1    Timer output is logic zero when enabled and is not affected by timer reset. TIMDEC = 2    Decrement counter on Pin input (both edges), Shift clock equals Pin input. TIMRST = 0    Timer never reset. TIMDIS = 6    Timer disabled on Trigger rising edge. TIMENA = 6    Timer enabled on Trigger falling edge. TSTOP  = 0    Stop bit is disabled. TSTART = 1    Start bit enabled. Timer Control 0 Register (FLEXIO_TIMCTL0) = 0x04C00103 TRGSEL = 4    Trigger select. Pin 2 input. TRGPOL = 1    Trigger active low. TRGSRC = 1    Internal trigger selected. PINCFG = 0    Timer pin output disabled. PINSEL = 1    Timer pin 1 select. PINPOL = 0    Pin is active high. TIMOD  = 3    Single 16-bit counter mode. Timer Compare 0 Register (FLEXIO_TIMCMP0) = 0x0000000F TIMCMP = 0x0000000F Configure 8-bit transfer. Set TIMCMP = (number of bits x 2) - 1. The shifter status flag is set every time the SHIFTBUF register has been loaded with data from the shifter. This occurs every time that the transmitter sends 8 bits of data. You can read the shifter status flag by polling or by enabling an interrupt based on your needs. This flag clears automatically when you read the SHITBUF register. During the transmission, the first thing that happens is that timer from the receiver will be enabled because the chip select signal from the transmitter is configured as a trigger. Once the timer is enabled, the timer will begin to decrement on the pin input, this means that the shifter clock of the receiver will be equal to the pin input. The transmitter shifter is configured to shift data out on the positive edge of the clock and the receiver shifter is configured to shift data in on the negative edge of the clock. After 8 bits have been transmitted, the compare register from the receiver will reach 0 and this generates an event to store the data from the shifter to the SHITBUF register and the Shifter Status Flag will be set. Finally the timer will be disabled by the chip select signal and keep waiting for another transaction. The hardware connections are shown in the following table. Signal name TWR-KL43Z48M transmitter TWR-KL43Z48M receiver Pin name Board Location Pin name Board Location Serial Data PTD0/FXIO0_D0 B46 PTD0/FXIO0_D0 B46 Clock PTD1/FXIO0_D1 B48 PTD1/FXIO0_D1 B48 Chip Select PTD2/FXIO0_D2 B45 PTD2/FXIO0_D2 B45 GND GND B2 GND B2 Table 1. Hardware connections Figure 8. Hardware connections The example projects for the FlexIO transmitter and receiver are developed in KDS 3.0.0 with KSDK 1.2.0. The application lets the user communicate with the transmitter via a serial terminal and the transmitter sends each character to the receiver via FlexIO and the receiver displays the received character on another serial terminal. To be able to compile the project, first you need to compile the library located in C:\Freescale\KSDK_1.2.0\lib\ksdk_platform_lib\kds\KL43Z4. Once the two TWR-KL43Z48M are connected as described above, import both projects into KDS, compile the platform library, and both projects. Open two serial terminals configured to 115200 bauds and run each project on a different tower. On the transmitter terminal you can write anything and it will be displayed and transmitted to the receiver tower via FlexIO and will be shown on the other terminal. Figure 9. FlexIO example application. Transmitter (left terminal). Receiver (Right terminal). The FlexIO module is also capable of generating a PWM signal by configuring one of its timers to the Dual 8-bit counters PWM mode. This mode is configured by writing 01 to TIMOD in the TIMCTL register. In this mode, the lower 8-bits of the counter and compare register are used to configure the high period of the timer output and the upper 8-bits are used to configure the low period of the timer output. The shifter bit count is configured using another timer or external signal. To calculate the frequency of the PWM signal you have to add the lower 8-bits of the counter and the upper 8-bits and divide it by the FlexIO clock*2 (Only if the timer is configured to decrement on the FlexIO clock.) The frequency of the PWM signal is given by: f = (FlexIO clock)/(TIMCMP[15:8]+TIMCPM[7:0]+2) To calculate the TIMCMP values to get a certain frequency you can solve the equation for TIMCMP TIMCMP[15:8]+TIMCPM[7:0] = (FlexIO clock)/f-2 For example, let’s say we want a 200kHz PWM signal, by using the formula above and using the FlexIO clock of 48MHz, we get that the sum of the TIMCMP values must be 238. If we want a 50% duty cycle we need to write the value 238/2 to the lower and upper 8 bits of the TIMCMP register. The waveform generated by these settings is shown in the figure below. Figure 10. 200kHz 50% duty cycle PWM signal To change the duty cycle you need to change the values of TIMCPM[15:8] and TIMCPM[7:0] but without changing the sum of both values, otherwise the frequency will also be altered. For example, if we need a 20% duty cycle we multiply 0.20*238 and 0.8*238. We round up the results and get TIMCPM[7:0] = 48 and TIMCPM[15:8] = 190. The waveform generated will look as shown in the figure below. Figure 11. 200kHz 20% duty cycle PWM signal
View full article
Hi community!! The following example uses a PIT to start an adc conversion, once the conversion has finished it issues a DMA request and the DMA controller stores the converted value in a buffer. The examples were implemented in both CodeWarrior 10.6 and KDS 1.1 for every board. The recommended test circuit is the following: Please feel free to modify the files, I hope this examples will be useful for you and will help you by decreasing your development time. Best Regards Manuel Rodríguez Technical Information Center Intern
View full article
for M68HC08, HCS08, ColdFire and Kinetis MCUs by: Pavel Lajsner, Pavel Krenek, Petr Gargulak Freescale Czech System Center Roznov p.R., Czech Republic The developer's serial bootloader offers to user easiest possible way how to update existing firmware on most of Freescale microcontrollers in-circuit. In-circuit programming is not intended to replace any of debuging and developing tool but it serves only as simple option of embedded system reprograming via serial asynchronous port or USB. The developer’s serial bootloader supported microcotrollers includes 8-bit families HC08, HCS08 and 32-bit families ColdFire, Kinetis. New Kinetis families include support for K series and L series. This application note is for embedded-software developers interested in alternative reprogramming tools. Because of its ability to modify MCU memory in-circuit, the serial bootloader is a utility that may be useful in developing applications. The developer’s serial bootloader is a complementary utility for either demo purposes or applications originally developed using MMDS and requiring minor modifications to be done in-circuit. The serial bootloader offers a zero-cost solution to applications already equipped with a serial interface and SCI pins available on a connector. This document also describes other programming techniques: FLASH reprogramming using ROM routines Simple software SCI Software for USB (HC08JW, HCS08JM and MCF51JM MCUs) Use of the internal clock generator PLL clock programming EEPROM programming (AS/AZ HC08 families) CRC protection of serial protocol option NOTE: QUICK LINKS The Master applications user guides: Section 10, Master applications user guides. The description of Kinetis version of protocol including the changes in user application: Section 7, FC Protocol, Version 5, Kinetis. The quick start guide how to modify the user Kinetis application to be ready for AN2295 bootloader: Section 7.8, Quick guide: How to prepare the user Kinetis application for AN2295 bootloader. Full application note and  software attached.
View full article
When you go with your laptop to a public place and you don't have a wi-fi connection available you can connect your cellphone in the USB port of your computer, turn on the USB tethering feature of your smartphone and you get full acess to the internet using your carrier data plan. The USB tethering uses the the RNDIS protocol and is easy to implement on a laptop.   But how to connect a Kinetis to the internet using a cellphone?   I'm sharing the the first version of the implementation I made of the RNDIS protocol.It's based in the KSDK 1.3 + MQX + LwIP and it can be used for reference in other projects. It's only a first release and I plan some additional implementation, bugfixes and support for other Kinetis boards in the near future but it already can be useful in some projects. Initially it only supports FRDM-K22F and FRDM-K64F but it can be implemented in any MCU with USB controller and enough FLASH. It's a low-cost and simple way to connect your MCU to the internet when you don't have a Ethernet cable available or an Wi-fi connection or a 4G module available in your board.   Introduction   This project implements the RNDIS protocol on the top of the USB Host Stack and in the bottom of the LwIP (TCP/IP stack). When a cellphone is connected to a freedom board, it acts as a USB device and the Freedom board acts as a host.   * Software implementation * Cellphone connected to a FRDM-K64F providing internet connection to the board   The user can design his own software in the top of the TCP/IP stack (LwIP) like if it's connected through an ethernet cable.   Demonstration   To run the demo you will need the KDS 1.3 (www.nxp.com/kds).   To load all the projects needed to your project you have to extract the .zip file and in KDS go to File -> Import, Project of Projects -> Existing Project Sets, and browse to the *.wsd file present in the folder:   USB_RNDIS\KSDK_1.3.0\examples\[your board]\demo_apps\lwip\usb_tethering_demo\usb_tethering_demo_mqx\kds   It will import all the needed project in to your workspaces so you will be able to build all the projects and flash it into your board.   With the application flashed, open a Serial terminal with 115200kbps, 8N1 for the CDC interface of OpenSDA.When the board starts, it will display:     Connect your cellphone in to the USB of the MCU. After connect the phone turn on the USB tethering feature and wait some seconds:   The Freedom Board will be connected to the internet. As an example, this demo connects to an HTTP server in the internet, download to MCU some data (Lastest news from an newspaper website) and displays it through the Serial connection.   You can modify this demo for your own application, using the TCP/IP and UDP/IP provided by the LwIP.   Typical Aplications   - Low-cost temporary internet connectivity to the MCU. - Remote updat (i.e.: bootloader through USB downloading the new firmware direct from the web) - Remote control - Remote diagnostics   Known Issues and Limitations: - This first version was only full implemented for FRDM-K22F and FRDM-K64F. I can implement for other boards through requests. - It was tested on Android Phones (Samsung Galaxy, Motorola G, Motorola X). I don't have a iPhone to test yet. - Some cellphones need additional current to detect that is attached to a host.A external power is needed in this situation.For FRDM-K64F I suggest to use the J27 footprint to provide 5V and short the diode D13. - Not all the RNDIS messages was implemented yet, only the most fundamental ones. - There's a flash size limitation due the size of the TCP/IP stacks ( that requires a considerably space of flash). It can adapted in the future for stacks with smaller footprint. - Only support KDS 3.0 at this time. And it only supports MQX at this time.   Let me  know if you have any question. Hope it can be useful!   1-      With the application flashed, open a Serial terminal with 115200kbps, 8N1 for the CDC interface of OpenSDA.When the board starts, it will display:
View full article
Revise History: Version 23: NXP kinetis bootloader GUI upgrade from v1.0 to v1.1: added 04 extended linear address record  and 02 sector address record processing for hex format. This article describes how to do in-system reprogramming of Kinetis devices using standard communication media such as SCI. Most of the codes are written in C so that make it easy to migrate to other MCUs. The solution has been already adopted by customers. The pdf document is based on FRDM-KL26 demo board and Codewarrior 10.6.  The bootloader and user application source codes are provided. GUI and video show are also provided. Now the bootloader source code is ported to KDS3.0, Keil5.15 and IAR7.40 which are also enclosed in the SW package. Customer can make their own bootloader applications based on them. The application can be used to upgrade single target board and multi boards connected through networks such as RS485. The bootloader application checks the availability of the nodes between the input address range, and upgrades firmware nodes one by one automatically. ​ Key features of the bootloader: Able to update (or just verify) either single or multiple devices in a network. Application code and bootloader code are in separated projects, convenient for mass production and firmware upgrading. Bootloader code size is small, only around 2K, which reduces the requirement of on chip memory resources. Source code available, easy for reading and migrating. GUI supports S19,HEX and BIN format burning images. For more information, please see attached document and code. The attached demo code is for KL26 which is Cortex - M0+ core. For Cortex-M4 core demo, refer this url: https://community.freescale.com/docs/DOC-328365 User can also download the document and source code from Github: https://github.com/jenniezhjun/Kinetis-Bootloader.git Thanks for the great support from Chaohui Guo and his team. NOTE: The bootloader and GUI code are all open source, users can revise them based on your own requirement. Enjoy Bootloader programming 🙂
View full article
This is an adaptation I made for the original SMTP protocol implementation provided with the KSDK1.3, with the addition of the secure connection using WolfSSL. The example software is currently ported to the FRDM-K64F Kinetis board but it can be implemented for other boards.This demo sends a e-mail using the Gmail SMTP server ( smtp.gmail.com , port 465) through a SSL channel.   How to run the example:   1 - Download the example software attached. You will need to have KDS 3.0 and KSDK1.3 previously installed on the machine. 2 - In KDS, go to File -> Import, select the folder Project of Projects -> Existing Project Sets, then open the file mqx_smtp_ssl_demo.wsd located in the folder \SMTP_SSL_demo_KSDK_1.3.0\examples\frdmk64f\demo_apps\security\smtp_wolfssl\smtp_wolfssl_mqx\kds 3- Build all the libraries and run the example project. 4- To allow SMTP + SSL , you will need to change your Gmail account settings 5- Using a Serial terminal (115200 bps,8N1) connected to the OpenSDA CDC interface (COM port), connect it to see the shell.Type ipconfig init and ipconfig dhcp to init the Ethernet interface and get a valid IP from the router.   6- Type help to see all the commands available. 7- To send a e-mail using the secure channel, you will need a valid gmail account and use the command:        sec_email -f <sender@email.com > -t <recipient@email.com> -s <www.mail.server.com> [-u <Username>] [-p <Password>] [-j <"email subject">] [-m <"text of email message"]>   For example:        sec_email -f user@gmail.com -t recipient@email.com -s smtp.gmail.com -u user@gmail.com -p mypassword -j "email subject" -m "text of email message"   Some additional notes:   - The Certificate Authority (CA) file from Equifax, used for Gmail, is decoded in hexadecimal to a c array and it is located in the file rtcs_smtp_ssl.c , in the \middleware\tcpip\rtcs\source\apps folder:     - To connect to other servers with SSL support, you will need to obtain a valid Certificate Authority file for this server. You can do it in three steps: 1) Verify what is the certificate authority used by the server. One way to do it is using OpenSSL ( OpenSSL  ) ,  with s_client and the option -showcerts to see the server certificates and check the certificate Authority.Gmail uses Equifax as CA 2) After you know the Certificate Authority of the server, you can get the certificate file in pem file format on a e-mail client for PC (e.g. Outlook).In this case , Outlook has the Equifax certificate file.All the certificate files need to start with -----BEGIN CERTIFICATE----- and to finish with -----END CERTIFICATE----- ,as below 3) You need to convert your CA file to a c language array. You can use Bin2h to do the task.        PEM file generated by Equifax before to be converted to a c array   All the files used to build the demo are included on the file attached. The SSL connection using the WolfSSL software is made on the file rtcs_smtp_ssl.c.
View full article
Hi All Kinetis Lovers, Microcontroller programming is a passion for all we are following this Community, but sometimes, trying to understand the peripherals of a Microcontroller is not an easy task, especially if we are in our first approach to a new module or device. In this post you will find a document that explains in detail the DMA module for Kinetis devices and also some examples for CodeWarrior and Kinetis Design Studio using DMA and other peripherals. The Documentation found here is: Using DMA module in Kinetis devices (complete): Document that includes DMA module explanation: everything you need to know when using DMA and the necessary information to understand the code included (K20_DMA for CW or K20D72_DMA for KDS). Using DMA module in Kinetis devices (example): Document that includes the necessary information to understand the code included (K20_DMA for CW or K20D72_DMA for KDS). Attached are two folders named: DMA examples for CW: include the DMA example projects for CW DMA examples for KDS: include the DMA example projects for KDS. Each folder includes 5 examples that are: Please feel free to modify the examples; I hope this will be useful for you. Many thanks and credits to manuelrodriguez for his valuable help developing and editing this project. :smileyinfo:For the SPI examples it is necessary to make a bridge between MOSI and MISO pins (master loop mode is used for the example). For this the TWR Elevators were used.     In the attachments you can find some extra information when using SPI and DMA. Best Regards, Adrian Sanchez Cano Technical Support Engineer
View full article
1. How Calibration works There are three main sub-blocks important in understanding how the Kinetis SAR module works.  There is a capacitive DAC, a comparator, and the SAR engine that controls the module. Of those blocks, the DAC is most susceptible to variations that can cause linearity problems in the SAR. The DAC is architected with three sets of binary weighted capacitors arrayed in banks, as in Figure 1. The capacitors that represent the most significant bits of the SAR (B15:B11) are connected directly to the inputs of the comparator. The next bank of five capacitors (B10:B6) is connected to the top plate of the MSB array through an intentionally oversized scaling capacitor. The final six capacitors that makeup the least significant bits of the SAR (B5:B0) are correspondingly connected to the top plate of the middle bank of capacitors through another scaling capacitor. Figure 1. Arrangement of DAC capacitors Only the MSB capacitor bank is calibrated. Because the first scaling capacitor is intentionally oversized, each of the non-calibrated MSB capacitors will have an effective capacitance too small to yield accurate results. However, because they are always too small, we can measure the amount oferror that each of those capacitors would cause individually, and add that back in to the result. Calibration starts with the smallest of the LSB capacitors, B11. The SAR samples Vrefl on all of the capacitors that are lower-than or equal-to the capacitor under test (CUT), while connecting all of the smaller capacitors to Vrefh. The top plate of all of the MSB capacitors is held at VDDA while this happens. After the sampling phase is complete, the top plates of the MSB capacitors are allowed to float, and the bottom plates of the MSBs not under test are connected to Vrefl. This allows charge to redistribute from the CUT to the smaller capacitors. Finally, an 11 bit SAR algorithm (corresponding with the 11 capacitors that are smaller than the MSB array) is performed which produces a result that indicates the amount of error that the CUT has compared to an ideally sized capacitor. This process is repeated for each of the five MSBs on both the plus side and minus side DACs and the five error values that are reported correspond to the five MSBs accordingly. All of these error values are about the same magnitude, with a unit of 16-bit LSBs. See Figure 2 for an example. Figure 2. Example of calibration on bit 11 The DAC MSB error is cumulative. That is, if bit 11 of the DAC is set, then the error is simply the error of that bit. However if bit 12 of the DAC is set, the total error is equivalent tothe error reported on bit 12, plus the error reported on bit 11. For each MSB the error is calculated as below, where Ex is the error found during the calibration for its corresponding MSB bit: When bit 11 of the DAC is set: CLx0 = E0. When bit 12 of the DAC is set: CLx1 = E0+E1. When bit 13 of the DAC is set: CLx2 = E2 + E1 + 2E0. When bit 14 of the DAC is set: CLx3 = E3 + E2 + 2E1 + 4E0. When bit 15 of the DAC is set: CLx4 = E4 + 2E3 + 4E2 + 8E1 + 16E0 Figure 3. Effect of calibration error on ADC response These are the values that are then placed in each of the CLxx calibration results registers. Figure 3 shows how the errors would accumulate if all of the CLxx registers were set to zero. The offset and gain registers are calculated based on these values as well. Because of this, the gain and offset registers calibrate only for errors internal to the SAR itself. Self calibration does not compensate for board or system level gain or offset issues. 2. Recommended Calibration Procedure From the above description it is evident that the calibration procedure is in effect several consecutive analog to digital conversions. These are susceptible to all of the same sources of error of any ADC conversion. Because what is primarily being measured is the error in the size of the MSB capacitors; the recommendation is to configure the SAR in such a way as to make for the most accurate conversions possible in the environment that the SAR is being calibrated in. Noise is the primary cause of run-to-run variation in this process,so steps should be taken to reduce the impact of noise during the calibration process. Such as: All digital IO should be silent and unnecessary modules should be disabled. The Vrefh should be as stable and high a voltage as possible, since higher Vrefh means larger ADC code widths. An isolated Vrefh pin would be ideal. Lacking that, using an isolated VDDA as the reference would be preferable to using VREFO. The clock used should be as noise free as possible, and less than or equal to 6 MHz. For this purpose the order of desirable clock sources for calibration would be OSC > PLL > FLL > ASYNC The hardware averaging should be set to the maximum 32 samples. The Low Power Conversion bit should be set to 0. The calibration should be done at room temperature. The High Speed Conversion and Sample Time Adder will not have much effect in most situations, and the Diff and Mode bits are completely ignored by the calibration routine. The calibration values should be taken for each instance of the SAR on a chip in the above conditions. They should be stored in nonvolatile memory and then written into their appropriate registers whenever the ADC register values are cleared. In some instances, the system noise present will still cause the calibration routine to exhibit greater than desired run-to-run variation. One rule of thumb would be to repeat calibration several times and look at the CLx0 registers. If the value reported in that register varies by more than three, the following procedure can be implemented. Run the calibration routine several times. Twenty to forty times. Place the value of each of the calibration registers into a corresponding array. Perform a bubble sort on each array and find the median value for each of the calibration registers. Use  these median values as described for typical calibration results.
View full article
Hello Kinetis community. Attached there is a guide on how to modify an existing KDS project to be loaded using the KBOOT Flash Resident bootloader. Basically it explains 2 procedures: 1- Manipulating linker file to move application and vectors. 2- Adding data for the Bootloader Configuration Area (BCA). I am also including 3 adapted KDS v3.0.0 example projects ready to be used with KBOOT Flash Resident bootloader in a FRDM-K22F: - Baremetal project. - KSDK project. - KSDK project with Processor Expert support. The application simply toggles the red, green and blue LEDs sequentially. I hope you find the document and projects useful! Regards! Jorge Gonzalez
View full article
Welcome to the FRDM-K64 mbed workshop, in this page you will find all the code examples we will review on this session. The program covers the following modules: GPIO Serial communication Interrupts PWM ADC I2C (Accelerometer) USB Ethernet Depending on how fast we advance during the session some of the modules might be skipped; however here you can find both the source code and binary files ready to be flashed into the FRDM-K64 development board. FRDM-K64Z120M The FRDM-K64 is fully compatible with the Arduino rapid prototyping system, the following image depicts the board's pinout, the green labels can be used directly into your mbed proyects, they have already been defined in the headers and libraries in order to make development easier. Sign up at mbed.org In order to create the projects covered on this session it is necessary to create an mbed user account, open the website and create a user account, if you have already signed up please log in. Mbed debugging application To enable the FRDM-K64 development board using the binary files generated by mbed it is necessary to update the board's firmware, follow the steps mentioned below in order to enable the board to be programmed: Press the board's reset button While pressing the reset button connect the board to your computer using the USB cable, it must be connected to the J26 USB connector. Once the unit has enumerated as "Bootloader", copy the 20140530_k20dx128_k64f_if_mbed.bin file into the unit Disconnect and reconnect the USB cable, the board must enumerate as "MBED" Serial communication driver To implement serial communication you need to install the serial driver in your computer, download the driver, once your board has enumerated as MBED execute the driver and wait for it to be finished, this might take a couple of minutes. Serial terminal In order to communicate with the board via serial port it is necessary to use a serial terminal, by default WIndows 7 and 8 do not have this application, XP does. If your OS does not feature a serial terminal, you can download the one at the bottom (Teraterm). ! Your board is now ready to be programmed using mbed!
View full article
@@This article describes how to do in-system reprogramming of Kinetis for Cortex-M4 core devices using standard communication media such as SCI. Most of the codes are written in C so that make it easy to migrate to other MCUs. The solution has been adopted by customers. This bootloader is based on FRDM-K22 demo board and KDS3.0. The bootloader and user application source codes are provided. GUI is also provided. Customer can make their own bootloader applications based on them. The application can be used to upgrade single target board and multi boards connected through networks such as RS485. The bootloader application checks the availability of the nodes between the input address range, and upgrades firmware nodes one by one automatically. Key features of the bootloader: Able to update (or just verify) multiple devices in a network. Application code and bootloader code are in separated projects, convenient for mass production and firmware upgrading. Bootloader code size is small, only around 3k, which reduces on chip memory resources. Source code available, easy for reading and migrating. For Cortex-M0+ products, please refer to here :Kinetis Bootloader to Update Multiple Devices in a Network - for Cortex-M0+ , it based on FRDM-KL26. The main difference between Cortex-M4 and Cortex-M0+ is the FLASH program routine. - In Cotex-M4 core kinetis, we need copy the Flash operating routines to RAM. In the bootloader code, the copy to ram code is realized in the function of “FLASH_Initialization()”: Byte buffer[200]={0}; - In Cotex M0+ core kinetis, we do not need to copy the Flash operating routines to RAM. Platform Control Register (MCM_PLACR) is added. The MCM_PLACR register selects the arbitration policy for the crossbar masters and configures the flash memory controller. Enabling ESFC bit can stall flash controller when flash is busy.  Setting ESFC bit can well-balance time sequence of Flash reading and writing – when writing Flash, reading Flash instruction can wait, and vice versa. Using ESFC bit can make our flash programming easier. Thus one Flash can write itself, which is not possible for other one Flash MCU without ESFC bit control. ESFC bit is easy to be set in C code: For more information, please see attached document and code. User can also download the document and source code from Github: https://github.com/jenniezhjun/Kinetis-Bootloader.git
View full article
Here you can find both the code and project files for the Serial communication project, in this example the serial port (UART) is configured to establish communication between the computer using a serial terminal and the evaluation board. The default baud rate for the serial port is 9600 bauds. The code also implements an echo function, any key pressed in the computer's keyboard will be captured and displayed in the serial terminal. If your computer does not have a serial terminal you can download Tera Term from the following link: Tera Term Open Source Project The communication is established through the USB cable attached to the OpenSDA USB port. Code: #include "mbed.h" //Digital output declaration DigitalOut Blue(LED3); //Serial port (UART) configuration Serial pc(USBTX,USBRX); int main() {     Blue=1;     pc.printf("Serial code example\r\n");        while(1)     {         Blue=0;         pc.putc(pc.getc());     }    }
View full article
Although most of us have a basic understanding of how an ADC works and how to understand some of the basic figures that define an ADC performance, that is far from really understanding how to fully interpret and use the figures depicted in a datasheet ADC section. With all those numbers it is easy to get lost on which ones to look at when we want to know how it will react to conditions such as frequency, signal amplitude, temperature, etc; having such knowledge would allow us to better fit a specific ADC to your application and take full advantage of its features. Having this in mind I took the time to compile some information related to what the most common figures that describe an ADC performance depicted in a datasheet mean, most of the material can be found in any Analog to Digital Conversion theory book; as I mentioned before this is just a general compilation of knowledge I hope will help you better understand those specifications. It assumes those of us who use datasheets are somehow familiar with the basic working of ADCs, so I will spare the basic concepts. Now down to business, this is a extract of a typical ADC section from a microcontroller's datasheet: I am almost certain not a lot of people who use microcontrollers, and more specifically ADCs; have a clear idea of what Total Unadjusted Error, Integral Non-Linearity or Differential Non-Linearity describe in the behavior of an ADC. Even though I will try to describe in detail the most common parameters I might miss some others and there is the possibility some of the information might not be as accurate as I would like it to be, if any of you reading this brief document have specific questions regarding any parameter I describe or miss by all means comment. Common ADC electrical characteristics depicted in datasheets EQ          Quantization error      Since the analog input to an ADC can take any value, but the digital output is quantized, there may be a difference of up to ½ Less Significant Bit between the actual analog input and the exact value of the digital output. This is known as the quantization error or quantization uncertainty as shown below. In ac (sampling) applications this quantization error gives rise to quantization noise. SINAD, SNR and ENOB (Signal to Noise plus Distortion, SIgnal to Noise Ratio and Effective Number of Bits)      Signal-to-Noise-and Distortion (SINAD, or S/(N + D) is the ratio of the rms signal amplitude to the mean value of the root-sum square (rss) of all other spectral components, including harmonics, but excluding dc. SINAD is a good indication of the overall dynamic performance of an ADC      as a function of input frequency because it includes all components which make up noise (including thermal noise) and distortion. It is often plotted for various input amplitudes. SINAD is equal to THD + N if the bandwidth for the noise measurement is the same. SINAD is often converted      to effective-number-of-bits (ENOB) using the relationship for the theoretical SNR of an ideal N-bit ADC: SNR = 6.02N + 1.76 dB, the equation is solved for N, and the value of SINAD is substituted for SNR.      Effective number of bits (ENOB) is a measure of the dynamic performance of an analog to digital converter and its associated circuitry. The resolution of an ADC is specified by the number of bits used to represent the analog value, in principle giving 2 N signal levels for an N-bit signal. However, all real ADC circuits introduce noise and distortion. ENOB specifies the resolution of an ideal ADC circuit that would have the same resolution as the circuit under consideration. Often ENOB is calculated using the relationship for the theoretical SNR of an ideal N-bit ADC: SNR =      6.02N + 1.76 dB, the equation is solved for N, and the value of SINAD is substituted for SNR. SFDR      Spurious Free Dynamic Range     One of the most significant specification for an ADC used in a communications application is its spurious free dynamic range (SFDR). SFDR of an ADC is defined as the ratio of the rms signal amplitude to the rms value of the peak spurious spectral content measured over the bandwidth      of interest. SFDR is generally plotted as a function of signal amplitude and may be expressed relative to the signal amplitude (dBc) or the ADC full-scale (dBFS) as shown in Figure n. For a signal near full-scale, the peak spectral spur is generally determined by one of the first few harmonics of the fundamental. However, as the signal falls several dB below full-scale, other spurs generally occur which are not direct harmonics of the input signal. This is because of the differential nonlinearity of the ADC transfer function as discussed earlier. Therefore, SFDR      considers all sources of distortion, regardless of their origin. INL      Integral Non-Linearity     Integral nonlinearity (acronym INL) is the maximum deviation between the ideal output of an ADC and the actual output level (after offset and gain errors have been removed). The transfer function of an ADC should ideally be a line and the INL measurement depends on the ideal line selected. Two often used lines are the best fit line, which is the line that minimizes the INL result and the endpoint line which is a line that passes through the points on the transfer function corresponding to the lowest and highest input code. In all cases, the INL is the maximum distance between the ideal line selected and the actual transfer function. DNL        Differential Non-Linearity      Differnetial NonLinearity relates to the linearity of the code transitions of the converter. In the ideal case, a change of 1 LSB in digital code corresponds to a change of exactly 1 LSB of analog signal. In an ADC there should be exactly 1 LSB change of analog input to move from one           digital transition to the next. Differential linearity error is defined as the maximum amount of deviation of any quantum (or LSB change) in the entire transfer function from its ideal size of 1 LSB. Where the change in analog signal corresponding to 1 LSB digital change is more or less than 1 LSB, there is said to be a DNL error. The DNL error of a converter is normally defined as the maximum value of DNL to be found at any transition across the range of the converter. The following figure shows the non-ideal transfer functions for an ADC and shows the effects of the DNL error.      A common result of excess DNL in ADCs is missing codes resulting from DNL < –1 LSB. THD      Total Harmonic Distortion Total harmonic distortion (THD) is the ratio of the rms value of the fundamental signal to the mean value of the root-sum-square of its harmonics (generally, only the first 5 are significant). THD of an ADC is also generally specified with the input signal close to full-scale, the harmonics of the input signal can be distinguished from other distortion by their location in the frequency spectrum. The second and third harmonics are generally the only ones specified on a data sheet because they tend to be the largest. EFS     Full Scale Error Full-scale error can be defined as the difference between the actual value triggering the transition to full-scale and the ideal analog full-scale transition value. Full-scale error is equal to the offset error + gain error Offset error The transfer characteristics of both DACs and ADCs may be expressed as a straight line given by D = K + GA, where D is the digital code, A is the analog signal, and K and G are constants. In a unipolar converter, the ideal value of K is zero. The offset error is the amount by which the actual value of K differs from its ideal value. Gain error The gain error is the amount by which G differs from its ideal value, and is generally expressed as the percentage difference between the two, although it may be defined as the gain error contribution (in mV or LSB) to the total error at full-scale. TUE      Total Unadjusted Error This is the result of performing conversions without having calibrated the ADC, it is dominated by the uncalibrated gain and uncalibrated offset terms in the data sheet. Although most devices will be well within the data sheet limits, it should be noted that they are not centered around zero and full range of the incoming analog signal is not guaranteed. Therefore, an uncalibrated ADC will always show unknown levels of gain and offset error, thus reflecting the worst case of conversion error the module can provide.
View full article
客户要求:K60 100MHz芯片作为SPI主机读取片外SPI Flash存储器内容(SPI Flash器件数据准备完成会触发K60 GPIO中断),要求在130~150微秒之间读取九个不连续地址上的数据,每个地址需要读取4个字节,SPI波特率为5MHz。读取SPI Flash存储器,需要使用读取命令(1个字节)外加地址(2个字节)。换言之,每读取一次K60需要发送7个字节(1字节读取命令+2字节地址+4字节空读数据)。同时要求减少内核负担。 Customer requirement: Use K60 100MHz product as SPI master communicate with external SPI Flash device (When data ready, SPI Flash device will trigger K60 GPIO interrupt), it need to read data from 9 discontinuous address, each address read 4 bytes within 130~150us. SPI  baud rate is 5MHz. Read data from SPI Flash, it need SPI master send 1byte read command and 2bytes address. In another word, K60 need to send 7bytes(1byte read command+2bytes address+4bytes dummy read) 9times within 130us. SPI communication baud rate is 5MHz. It also require to reduce core work load. 实现方法:使用DMA模块,其中一个DMA通道1用来装载SPI传输TX数据(触发源为SPI TFFF符号,SPI FIFO可装载),另外一个DMA通道0用来接收SPI数据(触发源为SPI RFDF符号,SPI 接收FIFO非空)。通过使用DMA引擎可以自动发起SPI传输,减少内核在SPI传输过程中的干预,达到降低内核工作负荷的效果。SPI模块采用中断方式。 Reality way: Use DMA module, DMA CH0 loads data for SPI transmit, DMA CH1 stores data for SPI receive.  DMA triggered by SPI module and SPI module works in interrupt way. 测试平台:TWR-K60D100M, TWR-MEM, IAR ARM Workbench V6.60 TWR-MEM板子提供SPI Flash设备(AT26DF081A),可以通过TWR-K60D100M SPI2模块进行访问。 Test platform: TWR-K60D100M ,TWR-MEM , IAR ARM Workbench V6.60 SPI Flash AT26DF081A on TWR-MEM board, which could be accessed by TWR-K60D100M via SPI2 module. 测试场景一:读取AT26DF081A设备ID信息 Test scenario 1:  Read device ID AT26DF081A设备提供查询设备ID命令0x9F,返回4个字节设备ID信息(0x1F,0x45,0x01,0x00)。K60作为SPI主机发出查询命令,之后执行4次空写入操作用来读出设备ID信息。测试中SPI传输/接收数据帧大小设定为1个字节(8bit)。由于DSPI模块传输接收均提供4级FIFO,测试中使用两种方式进行SPI数据发送,一种方式使用DMA通道发送读取设备ID查询命令和4次空写入数据,另一种方式通过执行代码(需要内核干预)发送读取设备ID查询命令和4次空写入数据。SPI数据接收均使用DMA完成。为了便于测试使用DMA模块是否降低内核负荷,在DSPI通信同时,主程序在While循环中不停翻转GPIO引脚(PTD7)。 SPI Flash AT26DF081A provides read device ID command(0x9f), will feedback 4 bytes device ID info(0x1F,0x45,0x01,0x00)。K60 works as SPI master send read ID command, then send 4 dummy write data to read back device ID info. During test, SPI data frame size setting to 1byte(8 bit). For DSPI module TX/RX FIFO is 4 entries, so there using two ways do SPI data transfer, one is using DMA CH1 send data, the other way using software code send data. SPI RX using DMA CH0 and in main while loop it will toggle PTD7 pin to show if using DMA module will reduce core work load. 测试流程图(方法一: 使用DMA CH1发送SPI数据): Test flow chart (Way1: Using DMA CH1 do SPI TX): 测试结果(Test Result): 执行一次读ID信息操作,需要花费12.96us,其中内核处理中断的时间为(2.56+2.72)= 5.28us。 根据客户要求,依照此方法每次发送3个字节,接收4个字节,SPI通信过程中内核负荷时间比率为 (5.28/16.16) =32.7% SPI read ID operation once, it will take 12.96us, includes core deal with interrupt time 5.28us. According to this way, customer want to TX 3bytes then RX 4bytes, during SPI communication core work load rate is 32.7% 测试流程图(方法二: 使用软件代码发送SPI数据): Test flow chart (Way2: Using software code do SPI TX): 测试结果(Test Result): 执行一次读ID信息操作,需要花费11.6us,其中内核处理中断的时间为(2.48+1.40)= 3.88us。 根据客户要求,依照此方法每次发送3个字节,接收4个字节,SPI通信过程中内核负荷时间比率为 (3.88/14.80) =26.2% SPI read ID operation once, it will take 11.6us, includes core deal with interrupt time 3.88us. According to this way, customer want to TX 3bytes then RX 4bytes, during SPI communication core work load rate is 26.2% 测试场景二:读取AT26DF081A设备9处不连续地址数据 Test scenario 2: Read 9 discontinue address data from AT26DF081A AT26DF081A设备提供读阵列命令(0x0B),可以连续读取多个字节数据。根据客户要求,测试读取9处不连续地址数据,每处读取4个字节。根据AT26DF081A设备要求,读阵列命令后需要再发送3个字节地址信息外加1个字节空写入数据,之后K60将会收到数据。即如果要读取4个字节数据,K60作为SPI主机需要发送9个字节数据(1个字节读阵列命令+3个字节地址+1个字节空写入+4个字节空写入)。测试中使用两个DMA通道进行SPI数据收发,两个DMA通道交替工作,DMA通道0(SPI接收)优先级高于DMA通道1(SPI发送)。完成9处数据采集后进入SPI中断,清除EOQ标志并且修正DMA通道配置,进行新的一轮9处数据读取测试。为了便于测试使用DMA模块是否降低内核负荷,在DSPI通信同时,主程序在While循环中不停翻转GPIO引脚(PTD7)。 SPI Flash AT26DF081A provides read array command (0x0B) to sequentially read a continuous stream of data out. With customer requirement, the test will read 9 discontinue address data, each address read 4 bytes data. AT26DF081A datasheet shows read array command with 3 bytes address and 1 dummy byte, then following will be data. In order to read 4 bytes data out, K60 as SPI master need TX 9 bytes data (1byte read array command + 3bytes address + 1byte dummy data + 4bytes dummy data). During the test, it using two DMA channels do SPI TX/RX, each channel alternatively work, DMA CH0(SPI RX) with higher priority than DMA CH1(SPI TX). When finish 9 discontinue address data receive, it will clear EOQ flag and refresh DMA CH0/1 setting in SPI interrupt for next round read 9 discontinue address data test. In main while loop it will toggle PTD7 pin to show if using DMA module will reduce core work load. 测试流程图(Test flow chart): 测试结果(Test Result): 读取AT26DF081A设备9处不连续地址数据,需要花费132.32us,其中内核处理中断的时间为2.6us。 根据客户要求,依照此方法每次发送3个字节,接收4个字节,重复9次。SPI通信过程中内核负荷时间比率为 (2.6/103.52) =2.5% SPI read ID operation once, it will take  132.32us , includes core deal with interrupt time 2.6us. According to this way, customer want to TX 3bytes then RX 4bytes, 9times,during SPI communication core work load rate is 2.5% DMA模块提供动态加载DMA传输控制描述符(TCD)功能,当需要连续多次执行SPI传输时,使用这种功能可以进一步减少内核负荷。 DMA module provides dynamic scatter/gather feature, which supports automatically loading a new TCD into a DMA channel. Using this feature will reduce core work load in SPI transfer continuously. 测试结果(使用DMA动态加载功能): Test Result(Using DMA dynamic scatter/gather feature ): 读取AT26DF081A设备9处不连续地址数据,需要花费130.68us,其中内核处理中断的时间为0.76us。 根据客户要求,依照此方法每次发送3个字节,接收4个字节,重复9次。SPI通信过程中内核负荷时间比率为 (0.76/101.88) =0.75% SPI read ID operation once, it will take 130.68 us , includes core deal with interrupt time 0.76us. According to this way, customer want to TX 3bytes then RX 4bytes, 9times,during SPI communication core work load rate is 0.75% 测试结论(Test conclusion) SPI通信过程中DMA模块使用方式不同对于减轻内核负荷作用差异明显。通常SPI进行大量数据传输接收,使用DMA模块能有效减少内核负荷。鉴于客户需求,使用测试场景二的方法可以有效降低内核负荷。 How to use DMA module to reduce core work load, different way lead to different result. In general, using DMA module do amounts of SPI data transfer will reduce core work load . According customer requirement, using test scenario 2 way reduce core work load dramatically。 为什么每次读操作之间需要SPI片选无效 (Why need deassert CS signal between each read operation)? 根据AT26DF081A手册要求,读ID命令和读阵列命令都需要使片选信号无效用以结束当前的读操作,换言之如果要开始新的读操作,需要结束之前的通信(使片选信号无效)。 AT26DF081A datasheet indicates deasserting the CS pin will terminate the read operation and put the SO pin into a high-impedance state. In order to start new read command operation, it need deassert the CS pin. 计算客户要求每次读命令间隔时间为SPI实际通信时间(以5MHz波特率发送7个字节重复9次 100.8us)加上内核处理中断时间。 According customer requirement SPI each read command interval time is SPI communication time (TX 7bytes 9times with 5MHz baud rate take 100.8us) add core deal with interrupt time. 测试代码(Test source code) 测试代码基于Kientis 100MHz Rev2例程中的[spi_demo]工程,将测试代码替换<spi_demo.c>和<isr.h>文件即可。 Test source code is based on KINETIS512_V2_SC (Kientis 100MHz Rev2 Example Project) [spi_demo] project, using test code instead of orignial <spi_demo.c>&<isr.h> files.
View full article
Here you will find the code and project files corresponding to the I2C-Accelerometer project. The accelerometer/magnetometer is connected to the I2C port, although bot the accelerometer and magnetometer are contained within a single package, they must be initialized individually. In this example the measurements from both devices (X,Y and Z axis) is performed and displayed at the serial terminal. In order to compile the project, the following library must be imported: FXOS8700Q.h Code: #include "mbed.h" #include "FXOS8700Q.h" //I2C lines for FXOS8700Q accelerometer/magnetometer FXOS8700Q_acc acc( PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1); FXOS8700Q_mag mag( PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1); //Temrinal enable Serial pc(USBTX, USBRX); MotionSensorDataUnits mag_data; MotionSensorDataUnits acc_data; int main() {     float faX, faY, faZ;     float fmX, fmY, fmZ;     acc.enable();     printf("\r\n\nFXOS8700Q Who Am I= %X\r\n", acc.whoAmI());     while (true)     {         acc.getAxis(acc_data);         mag.getAxis(mag_data);         printf("FXOS8700Q ACC: X=%1.4f Y=%1.4f Z=%1.4f  ", acc_data.x, acc_data.y, acc_data.z);         printf("    MAG: X=%4.1f Y=%4.1f Z=%4.1f\r\n", mag_data.x, mag_data.y, mag_data.z);         acc.getX(&faX);         acc.getY(&faY);         acc.getZ(&faZ);         mag.getX(&fmX);         mag.getY(&fmY);         mag.getZ(&fmZ);         printf("FXOS8700Q ACC: X=%1.4f Y=%1.4f Z=%1.4f  ", faX, faY, faZ);         printf("    MAG: X=%4.1f Y=%4.1f Z=%4.1f\r\n", fmX, fmY, fmZ);                 wait(1.0);     } }
View full article
Hello Kinetis fans, This time I bring to you a document which explains what is and how to configure scatter/gather feature which is present in the Enhanced Direct Memory Access (eDMA). This document includes an example project for the Kinetis Design Studio (KDS) which works in the FRDM-K64F board but the configuration is the same for any MCU which includes the eDMA peripheral. If you are interested in the channel linking feature, please take a look into the document What is and how to configure the eDMA channel linking feature​. I hope you find this document useful. Best regards, Earl Orlando Ramírez-Sánchez Technical Support Engineer NXP Semiconductors
View full article
在电机控制,Audio等很多应用中,我们经常会用到一些常见的正余弦,矩阵变换,FFT等一些DSP函数,提到DSP库,通常会想到使用ARM 公司提供的 CMSIS 库。CMSIS 库是ARM和一些半导体厂家针对Cortex-M系列制定的一套接口标准,包括针对内核操作的CMSIS-CORE API,针对DSP应用的CMSIS-DSP Library,针对RTOS的CMSIS-RTOS API,与外设接口的CMSIS-SVD以及提供Debug访问接口的CMSIS-DAP。 其中,又以DSP应用的CMSIS-DSP 库的应用最为广泛。针对Cortex-M4中的DSP功能,CMSIS-DSP部分提供了超过60多种功能的DSP算法库,尤其是随着Cortex-M4中集成了FPU硬件单元,CMSIS-DSP 库的应用也越来越广泛。 在KEIL 和IAR中都集成了对CMSIS的支持,然而在CodeWarrior中没有直接支持CMSIS,需要用户移植到自己的CW工程中,所以就需要使用者了解CMSIS的结构,手动添加库文件和头文件,并完成一些重要的编译参数配置。特别是有些芯片支持FPU浮点运算单元,有些不支持,在配置选项上差别很大。在飞思卡尔Kinetis系列芯片中,FPU浮点运算单元也是一个可选的部件,只有在名称中带有FN和FX的芯片才支持FPU硬件浮点功能,如MK60FN1M0, MK60FX512。本文档分别介绍在使用和不使用FPU的情况下如何一步步移植CMSIS的DSP库到自己的CodeWarrior工程中。 需要注意的是 FPU 单元是指的芯片上的一个独立于 CPU 处理的浮点运算单元,整个单元在大多数厂家的芯片中都是可以被使能和关闭的。相对于芯片,编译器也设置了相应的 FPU 功能开启/关闭的选项,在编译时需要告诉编译器是否开启 FPU 功能。编译器一旦开启 FPU 功能,在处理单精度浮点运算的语句时就会用带 V-开头的汇编指令进行编译。如果编译器使能了 FPU 功能,而芯片未开启 FPU 单元,程序运行到浮点语句时就会出现异常。相反,如果编译器未使能 FPU 功能,芯片即使开启了 FPU单元,程序还是会按照未使能 FPU 的代码进行处理。在本例程中,为对比分析是否采用FPU的编译指令差别以及在板的执行效率,选用Kinetis K70FN1M为实验对象。 硬件平台:TWR-K70F120M核心板      软件环境:CodeWarrior v10.5        CMSIS版本 :V3.2 一. 准备工作: 下载CMSIS的库,当前最新的版本为V3.2,解压后名称为CMSIS-SP-00300-r3p2-00rel1,其目录结构如下图。分别包含CMSIS-DSP, CMSIS-RTOS和CMSIS-SVD的库文件。在本Cortex M4的CMSIS-DSP的应用中,真正用到的文件包括CMSIS\Include中CM4相关的头文件,CMSIS\Lib\GCC文件夹中的库文件libarm_cortexM4l_math.a(软浮点)和libarm_cortexM4lf_math.a(硬浮点),以及Device\ARM\ARMCM4\include中外设访问相关的两个头文件。 二. 不使用K70的FPU浮点运算单元,移植CMSIS的DSP库到CW的步骤;      Step 1:    新建一个Baremental的工程,选择器件器件MK70FN1M0(支持硬件FPU);     Step 2:    选择Floating Point浮点运算实现的类型,即指定编译器将C代码编译成汇编代码时使用的规则; 在Floating Point四个选项含义如下: Software选项:表示不使用FPU硬件,而是使用GCC的整数算术运算来模拟浮点运算; Handware(-mfloat –abi=hard) 选项:表示使用FPU硬件来进行浮点运算,函数的参数直接传递到FPU的寄存器(s0-d0)中; Handware(-mfloat –abi=softfp)选项:表示使用FPU硬件来进行浮点运算,但是函数的参数传递到整数寄存器(r0-r3)中,然后再传递到FPU中; Handware(-mfloat –abi=softfp –fshort -double)选项:其配置项同上,只不过使能了fshort  double功能,并且此处的double数据的宽度等同于float; 有兴趣研究各个选项意义的可以参考CW for MCU技术文档的第3章,在本例程中使用的是软浮点,所以选择Software项。需要注意的是:此配置选项仅出现支持FPU硬件单元的芯片工程中,如MK60FN1M0, MK60FX512等,否则默认没有此选项,默认为软件浮点。 Step 3:    点击“Next”进入下图,选择使用Processor Expert,点击“Finish“完成工程的建立; Step 4:    进入当前工程的文件夹,新建文件夹CMSIS,从之前在准备步骤解压的CMSIS文件包\...\CMSIS-SP-00300-r3p2-00rel1\CMSIS中拷贝Include和Lib文件夹到当前工程新建的CMSIS文件夹。另外,拷贝\...\CMSIS-SP-00300-r3p2-00rel1\Device\ARM\ARMCM4\Include中的ARMCM4.h和system_ARMCM4.h到当前工程新建的CMSIS文件夹中; Step 5:    回到CodeWarrior主界面选择新建的工程文件,F5刷新可以看到CMSIS出现在工程文件中。其中Include是CMSIS库的一些头文件,包括M0+/M3/M4的一些头文件;在Lib文件中是已经编译好的库文件,ARM文件夹是使用在KEIL IDE中的库文件,G++文件夹是使用在IAR中的库文件,而由于当前CW工程使用的GCC的编译器,所以GCC文件夹才是CW需要的,因此,为缩减工程大小可以删除ARM和G++文件夹;     Step 6:    打开工程属性框,选择Target Processor的Float ABI为No FPU; Step 7:    在GCC Complier的Defined symbols中添加编译的宏定义ARM_MATH_CM4; Step 8:    在GCC Complier的Include paths中添加CMSIS库的头文件,路径为:工程目录\CMSIS\Include; Step 9:    在GCC C Linker的Miscellaneous项的Other objects中指定使用的库文件(位于CMSIS\Lib\GCC文件夹中)。因为本例程中不使用FPU,所以选择libarm_cortexM4l_math.a,此处需要特别注意,否则编译会报错; Step 10: 在ProcessorExpert.c文件中添加代码; #include <math.h> #include "arm_math.h" #define DELTA    (0.000001f) const float32_t testRefOutput_f32 = 1.000000000; const float32_t radians=1.047197533333333; float32_t  cosOutput, sinOutput, diff; float32_t cosSquareOutput,sinSquareOutput,testOutput; int main(void) {   int m,n;   PE_low_level_init();   cosOutput = arm_cos_f32(radians); /*求正余弦*/                   sinOutput = arm_sin_f32(radians);                                 arm_mult_f32(&cosOutput, &cosOutput, &cosSquareOutput, 1); /*求积运算*/   arm_mult_f32(&sinOutput, &sinOutput, &sinSquareOutput, 1);               arm_add_f32(&cosSquareOutput, &sinSquareOutput, &testOutput, 1); /*求和运算*/   diff = fabsf(testRefOutput_f32 - testOutput);  /* 求绝对值 */                 if(diff > DELTA)   {                         while(1)                                 {                                   for(m=0;m<2000;m++)                                                 for(n=0;n<200;n++){};                                                 D7_NegVal();                                 }     }                 } Step 11:    编译并下载Debug,在  sinOutput = arm_sin_f32(radians);处设置断点,可以看到CMSIS-DSP库中的正余弦浮点数运算函数运算正常,其反汇编的得到为普通的ARM指令(FPU 单元汇编指令通常在普通指令前加字母V,仅在 FPU 功能被使能时使用),完成一个正弦计算; 至此,完成了不使用K70的FPU浮点运算单元,移植CMSIS的DSP库到CW的步骤。     三.     使用K70的FPU浮点运算单元,移植CMSIS的DSP库到Codewarrior的步骤 使用K70的FPU硬件浮点运算单元,移植CMSIS的DSP库到Codewarrior的方法有两种:一种是按照上面软浮点的方式Step By Step的建立工程,步骤和上面二的步骤基本一致,主要的两个区别在于:(1). Step 2要选择Handware(-mfloat –abi=hard) 选项,(2). Step 9 改为libarm_cortexM4lf_math.a。另外一种就是在上面工程的基础上修改配置选项。鉴于方便,本教程采用第二种方案,完成在Codewarrior中调用CMSIS的DSP库,通过K70的FPU浮点运算单元执行浮点运算,即硬浮点。 Step 1:    打开工程属性对话框,选择Target Processor的Float ABI为FPU with hard vfp passing(-mfloat –abi=hard); Step 2:    在GCC Complier的Defined symbols中添加编译的宏定义:_VFPV4; Step 3: 在GCC C Linker的Libraries项的library search path中指定链接的规则,把上面工程中默认的"${MCUToolsBaseDir}/ARM_GCC_Support/ewl/lib/armv7e-m"修改为 "${MCUToolsBaseDir}/ARM_GCC_Support/ewl/lib/armv7e-m/fpu"; Step 4:    在GCC C Linker的Miscellaneous项的Other objects中指定使用的库文件(位于CMSIS\Lib\GCC文件夹中)。因为本例程中使用FPU,所以选择libarm_cortexM4lf_math.a,此处需要特别注意,否则编译会报错; Step 5:    完成以上配置后,编译工程并下载调试(此处建议编译之前先Clean一下整个工程),同样,在  sinOutput = arm_sin_f32(radians);处设置断点,可以看到CMSIS-DSP库中的正余弦浮点数运算函数运算正常,其反汇编的得到为FPU指令(FPU指令通常是指在普通指令前加字母V,仅在 FPU功能被使能时使用),并且在Register观察窗口中也多了个FPU寄存器列表,感兴趣的读者可以对比一下和前面实验汇编出代码的差异,此处不再赘述; 至此,分别完成了使用和不适用K70的FPU浮点运算单元情况下, CMSIS的DSP库到Codewarrior的移植。在实际应用中需要用到更多的DSP函数,在项目中直接调用即可。下一步, Just Enjoy The Convenience of  The CMSIS! 有一点需要说明的是,前文中讲到使用FPU单元需要两步设置:(1). 在编译器中开启相应的 FPU 功能选项;(2). 开启芯片FPU 单元。似乎我们前面的设置是完成了第一个步骤,然而第二个步骤呢?仔细查看_arm_atart.c文件,可以发现代码_fp_init()正是完成了开启芯片FPU单元的过程,如下图,是一个条件编译函数,这也就解释了为什么在上面Step 2中定义了_VFPV4,其本质也就是使能芯片的FPU单元,其具体实现可以查看ARM手册的第74页的描述。 #ifdef   __VFPV4__        //Step 2中的宏定义                 __fp_init();      // 开启芯片的FPU单元 #endif
View full article
Introduction With the growth of the Internet of Things (IoT), more and more applications are incorporating the use of sensors while also requiring power efficiency and increased performance.  A popular interface for these sensors is the I2C protocol. The I2C bus is a great protocol that is a true multi-master protocol and allows for each bus to contain many devices.  As the performance demand of the application grows, so will the speed of the I2C bus as it will be necessary to get more data from the sensors and/or at a faster rate.  Many applications may already have a need to operate an I2C bus at 400 kHz or more.  Higher data rates means the MCU core will need to spend more time servicing the I2C transactions.  The DMA module is one good way to free up the core in order to let it tend to other aspects of the application.  This can add much needed or much desired performance to applications.  Especially applications that may be using small, power efficient, single core MCUs. It may seem like an easy, straight-forward task to add I2C reads from a sensor to an application.  However I2C is a time sensitive protocol and consequently, so is the I2C peripherals on MCUs.  It is important to understand the time requirements and how to overcome them. The recommended approach is to use DMA to transfer the received I2C data to the desired buffer in your application software.  This document is going to outline how to setup your DMA and provide an example of how to do this for a KW40 device using the Kinetis SDK version 1.3.  The KW40 is being targeted because this is a small, power efficient MCU that incorporates a radio for your wireless applications and as such, it is likely that your application could need this DMA approach.  The KSDK version 1.3 is being targeted because this version of the SDK does not currently support DMA transactions for the I2C peripheral. Understanding the Kinetis I2C peripheral module Before getting into the specifics of creating a DMA enabled I2C driver, it is important to understand some basics of the Kinetis I2C peripheral module.  This module handles a lot of the low-level timing.  However the I2C registers must be serviced in a timely manner to operate correctly.  Take the case of a master reading data from a typical I2C sensor as shown in the diagram below. In the diagram above, the red lines indicate points in the transaction where software or DMA needs to interact with the I2C peripheral to ensure the transaction happens correctly.  To begin a transaction the core must change the MST bit which puts a start bit on the bus (marked by symbol ST).  Immediately following this, the core should then also write the target slave's address (Device Address) including the read/write bit (R/W).  Once this transaction is complete, the I2C will issue an interrupt and then the core should write the register address to be read from. Upon completion of that being put on the bus, the I2C will issue another interrupt and the master should then put a repeated start (SR) on the bus as well as the slave's address again.  Now the slave will send data to the master (once the master begins the transaction by issuing a dummy read of the I2C data register).  In the standard configuration, the I2C peripheral will automatically send the NAK or AK depending on the configuration of the TXAK bit in the I2C peripheral.  Because of this automation, it is important that this bit be handled properly and is configured one frame in advance. Furthermore, to ensure that the NAK bit is sent at the appropriate time, the TXAK bit must be set when the second to last byte is received.  The timing of this configuration change is very important to ensuring that the transaction happens properly. This document will describe how to use DMA to receive the data.  The DMA will be configured before the transaction begins and will be used to receive the data from the slave.  The document will also discuss options to handle proper NAK'ing of the data to end the transaction. Writing a DMA I2C master receive function The first step in adding DMA capability to your SDK driver is to create a new receive function with an appropriate name.  For this example, the newly created receive function is named I2C_DRV_MasterReceiveDataDMA.  To create this function, the I2C_DRV_MasterReceive function (which is called for both blocking and non-blocking) was copied and then modified by removing the blocking capability of the function. Then in this function, after the dummy read of the IIC data register that triggers the reception of data, the DMA enable bit of the I2C control register is written. /*FUNCTION********************************************************************** * * Function Name : I2C_DRV_MasterReceiveDataDMA * Description   : Performs a non-blocking receive transaction on the I2C bus *                 utilizing DMA to receive the data. * *END**************************************************************************/ i2c_status_t I2C_DRV_MasterReceiveDataDMA(uint32_t instance,                                                const i2c_device_t * device,                                                const uint8_t * cmdBuff,                                                uint32_t cmdSize,                                                uint8_t * rxBuff,                                                uint32_t rxSize,                                                uint32_t timeout_ms) {     assert(instance < I2C_INSTANCE_COUNT);     assert(rxBuff);       I2C_Type * base = g_i2cBase[instance];     i2c_master_state_t * master = (i2c_master_state_t *)g_i2cStatePtr[instance];             /* Return if current instance is used */     OSA_EnterCritical(kCriticalDisableInt);         if (!master->i2cIdle)     {         OSA_ExitCritical(kCriticalDisableInt);         return kStatus_I2C_Busy;     }         master->rxBuff = rxBuff;     master->rxSize = rxSize;     master->txBuff = NULL;     master->txSize = 0;     master->status = kStatus_I2C_Success;     master->i2cIdle = false;     master->isBlocking = true;     OSA_ExitCritical(kCriticalDisableInt);             while(I2C_HAL_GetStatusFlag(base, kI2CBusBusy));     I2C_DRV_MasterSetBaudRate(instance, device);         /* Set direction to send for sending of address. */     I2C_HAL_SetDirMode(base, kI2CSend);       /* Enable i2c interrupt.*/     I2C_HAL_ClearInt(base);     I2C_HAL_SetIntCmd(base, true);       /* Generate start signal. */     I2C_HAL_SendStart(base);       /* Send out slave address. */     I2C_DRV_SendAddress(instance, device, cmdBuff, cmdSize, kI2CReceive, timeout_ms);       /* Start to receive data. */     if (master->status == kStatus_I2C_Success)     {         /* Change direction to receive. */         I2C_HAL_SetDirMode(base, kI2CReceive);                 /* Send NAK if only one byte to read. */         if (rxSize == 0x1U)         {         I2C_HAL_SendNak(base);         }         else         {         I2C_HAL_SendAck(base);         }                 /* Dummy read to trigger receive of next byte in interrupt. */         I2C_HAL_ReadByte(base);                 /* Now set the DMA bit to let the DMA take over the reception. */         I2C_C1_REG(I2C1) |= I2C_C1_DMAEN_MASK;                 /* Don't wait for the transfer to finish. Exit immediately*/     }     else if (master->status == kStatus_I2C_Timeout)     {         /* Disable interrupt. */         I2C_HAL_SetIntCmd(base, false);                 if (I2C_HAL_GetStatusFlag(base, kI2CBusBusy))         {         /* Generate stop signal. */         I2C_HAL_SendStop(base);         }                 /* Indicate I2C bus is idle. */         master->i2cIdle = true;     }         return master->status; } After writing the DMA driver, a DMA specific transfer complete function must be implemented. This is needed in order for the application software to signal to the driver structures that the transfer has been completed and the bus is now idle. In addition, the DMA enable bit needs to be cleared in order for other driver functions to be able to properly use the IIC peripheral. void I2C_DRV_CompleteTransferDMA(uint32_t instance) {     assert(instance < I2C_INSTANCE_COUNT);     I2C_Type * base = g_i2cBase[instance];     i2c_master_state_t * master = (i2c_master_state_t *)g_i2cStatePtr[instance];         I2C_C1_REG(base) &= ~(I2C_C1_DMAEN_MASK | I2C_C1_TX_MASK);     I2C_C1_REG(base) &= ~I2C_C1_MST_MASK;;        /* Indicate I2C bus is idle. */     master->i2cIdle = true; } DMA Configuration Next, the application layer needs a function to configure the DMA properly, and a DMA callback is needed to properly service the DMA interrupt that will be used as well as post a semaphore. But before diving into the specifics of that, it is important to discuss the overall strategy of using the DMA in this particular application. After every transaction, the data register must be serviced to ensure that all of the necessary data is received.  One DMA channel can easily be assigned to service this activity.  After the reception of the second to last data byte, the TXAK bit must be written with a '1' to ensure that the NAK is put on the bus at the appropriate time. This is a little trickier to do.  There are three options: A second dedicated DMA channel can be linked to write the I2C_C1 register every time the I2C_D register is serviced.  This option will require a second array to hold the appropriate values to be written to the I2C_C1 register.  The following figure illustrates this process. The second DMA channel can be linked to write the I2C_C1 register after the second to last data byte has been received.  This option would require that the primary DMA channel be set to receive two data bytes less than the total number of desired data bytes.  The primary DMA channel would also need to be re-configured to receive the last two bytes (or the application software would need to handle this).  However this could be a desirable programming path for applications that are memory constrained as it reduces the amount of memory necessary for your application. The primary DMA channel can be set to receive two data bytes less than the total number of desired data bytes and the core (application software) can handle the reception of the last two bytes.  This would be a desirable option for those looking for a simpler solution but has the drawback that in a system where the core is already handling many other tasks, there may still be issues with writing the TXAK bit on time. This example will focus on option number 1, as this is the simplest, fully automatic solution.  It could also easily be modified to fit the second option as the programmer would simply need to change the number of bytes to receive by the primary DMA and add some reconfiguration information in the interrupt to service the primary DMA channel. DMA Channel #1 The first DMA channel is configured to perform 8-bit  transfers from the I2C data register (I2C_D) to the buffer to hold the desired data.  This channel should transfer the number of desired bytes minus one.  The final byte will be received by the core.  Other DMA configuration bits that are important to set are the cycle steal bit, disable request bit, peripheral request bit (ERQ), interrupt on completion of transfer (EINT), and destination increment (DINC).  It also important to configure the link channel control to perform a link to channel LCH1 after each cycle-steal transfer and LCH1 should be configured for the channel that will transfer from memory to the I2C control register (I2C_C1).  The first DMA channel is configured as shown below. // Set Source Address (this is the UART0_D register       DMA_SAR0 = (uint32_t)&I2C_D_REG(base);             // Set BCR to know how many bytes to transfer       // Need to set to desired size minus 1 because the last will be manually       // read.        DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(destArraySize - 1);             // Clear Source size and Destination size fields.        DMA_DCR0 &= ~(DMA_DCR_SSIZE_MASK                     | DMA_DCR_DSIZE_MASK                     );       // Set DMA as follows:       //     Source size is byte size       //     Destination size is byte size       //     D_REQ cleared automatically by hardware       //     Destination address will be incremented after each transfer       //     Cycle Steal mode       //     External Requests are enabled       //     Interrupts are enabled       //     Asynchronous DMA requests are enabled.       //     Linking to channel LCH1 after each cycle steal transfer       //     Set LCH1 to DMA CH 1.        DMA_DCR0 |= (DMA_DCR_SSIZE(1)             // 1 = 8-bit transfers                    | DMA_DCR_DSIZE(1)           // 1 = 8-bit transfers                    | DMA_DCR_D_REQ_MASK                    | DMA_DCR_DINC_MASK                    | DMA_DCR_CS_MASK                    | DMA_DCR_ERQ_MASK                    | DMA_DCR_EINT_MASK                    | DMA_DCR_EADREQ_MASK                    | DMA_DCR_LINKCC(2)          // Link to LCH1 after each cycle-steal transfer                    | DMA_DCR_LCH1(1)            // Link to DMA CH1                    );       // Set destination address       DMA_DAR0 = (uint32_t)destArray; DMA Channel #2 The second DMA channel, which is the linked channel, should be configured to perform 8-bit transfers that transfer data from an array in memory (titled ack_nak_array in this example) to the I2C control register (I2C_C1).  This channel should also disables requests upon completion of the entire transfer, and enable the cycle-steal mode.  In this channel, the source should be incremented (as opposed to the destination as in the first channel). This channel is configured as shown below: // Set Source Address (this is the UART0_D register       DMA_SAR1 = (uint32_t)ack_nak_array;             // Set BCR to know how many bytes to transfer       // Need to set to desired size minus 1 because the last will be manually       // read.       DMA_DSR_BCR1 = DMA_DSR_BCR_BCR(destArraySize - 1);             // Clear Source size and Destination size fields.        DMA_DCR1 &= ~(DMA_DCR_SSIZE_MASK                     | DMA_DCR_DSIZE_MASK                     );             // Set DMA as follows:       //     Source size is byte size       //     Destination size is byte size       //     D_REQ cleared automatically by hardware       //     Destination address will be incremented after each transfer       //     Cycle Steal mode       //     External Requests are disabled       //     Asynchronous DMA requests are enabled.       DMA_DCR1 |= (DMA_DCR_SSIZE(1)             // 1 = 8-bit transfers                    | DMA_DCR_DSIZE(1)           // 1 = 8-bit transfers                    | DMA_DCR_D_REQ_MASK                    | DMA_DCR_SINC_MASK                    | DMA_DCR_CS_MASK                    | DMA_DCR_EADREQ_MASK                    );             // Set destination address       DMA_DAR1 = (uint32_t)&I2C_C1_REG(base); Once the DMA channels are initialized, the only action left is to configure the interrupts, enable the channel in the DMA MUX, and create the semaphore if it has not already been created.  This is done as shown below. //Need to enable the DMA IRQ       NVIC_EnableIRQ(DMA0_IRQn);       //////////////////////////////////////////////////////////////////////////       // MUX configuration       // Enables the DMA channel and select the DMA Channel Source        DMAMUX0_CHCFG0 = DMAMUX_CHCFG_SOURCE(BOARD_I2C_DMAMUX_CHN); //DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x31); //0xb1;       DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK;             /* Create semaphore */       if(semDmaReady == NULL){         semDmaReady = OSA_EXT_SemaphoreCreate(0);       } Finally, the DMA initialization function also initializes the ack_nak_array.  This is only necessary when implementing the first DMA strategy.  The second DMA strategy would only need to write a single value at the correct time.  The array initialization for strategy #1 is shown below.  Note that the values written to the array are 0xA1 plus the appropriate value of the TXAK bit.  By writing 0xA1, it is ensured that the I2C module will be enabled in master mode with the DMA enable bit set. // Initialize Ack/Nak array       // Need to initialize the Ack/Nak buffer first       for( j=0; j < destArraySize; j++)       {           if(j >= (destArraySize - 2))           {               ack_nak_array[j] = 0xA1 | I2C_C1_TXAK_MASK;           }           else           {               ack_nak_array[j] = 0xA1 & (~I2C_C1_TXAK_MASK);           }       } DMA Interrupt Handler Now a DMA interrupt handler is required.  A minimum of overhead will be required for this example as the interrupt handler simply needs to service the DONE bit and post the semaphore created in the initialization.  The DMA interrupt handler is as follows: void DMA0_IRQHandler(void) {     // Clear pending errors or the done bit     if (((DMA_DSR_BCR0 & DMA_DSR_BCR_DONE_MASK) == DMA_DSR_BCR_DONE_MASK)         | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BES_MASK) == DMA_DSR_BCR_BES_MASK)         | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BED_MASK) == DMA_DSR_BCR_BED_MASK)         | ((DMA_DSR_BCR0 & DMA_DSR_BCR_CE_MASK) == DMA_DSR_BCR_CE_MASK))     {         // Clear the Done MASK and set semaphore, dmaDone         DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;         //dmaDone = 1;         OSA_SemaphorePost(semDmaReady);     } } Using your newly written driver function Once all of these items have been taken care of, it is now time for the application to use the functions. It is expected that the DMA will be initialized before calling the DMA receive function.  After the first call, the DMA can be re-initialized every time or could simply be reset with the start address of the arrays and byte counter (this is the minimum of actions that must be performed).  Then the application should ensure that the transaction happened successfully.   Upon a successful call to the I2C_DRV_MasterReceiveDataDMA function, the application should wait for the semaphore to be posted.  Once the semaphore posts, the application software should wait for the Transfer Complete flag to become set.  This ensures that the application does not try to put a STOP signal on the bus before the NAK has been physically put on the bus.  If the STOP signal is attempted out of sequence, the I2C module could be put in an erroneous state and the STOP signal may not be sent.  Next, the I2C_DRV_CompleteTransferDMA function should be called to send the STOP signal and to signal to the driver structures that the bus is idle.  At this point, the I2C transaction is now fully complete and there is still one data byte that hasn't been transferred to the receive buffer.  It is the application's responsibility to perform one last read of the Data register to receive the last data byte of the transaction. /* Now initialize the DMA */    dma_init(BOARD_I2C_INSTANCE, Buffer, ack_nak_buffer, FXOS8700CQ_READ_LEN); //Init DMAMUX       returnValue = I2C_DRV_MasterReceiveDataDMA(BOARD_I2C_INSTANCE, &slave,                                                   cmdBuff, 1, Buffer, FXOS8700CQ_READ_LEN, 1000); if (returnValue != kStatus_I2C_Success)    {        return (kStatus_I2C_Fail);    } /* Wait for the DMA transaction to complete */    OSA_SemaphoreWait(semDmaReady, OSA_WAIT_FOREVER);       /* Need to wait for the transfer to complete */ for(temp=0; temp<250; temp++)     {         if(I2C_HAL_GetStatusFlag(base, kI2CTransferComplete))         {             break;         }     }       /* Now complete the transfer; this includes sending the I2C STOP signal and       clearing the DMA enable bit */    I2C_DRV_CompleteTransferDMA(BOARD_I2C_INSTANCE);       // Once the Transfer is complete, there is still one byte sitting in the Data    // register.      Buffer[11] = I2C_D_REG(g_i2cBase[BOARD_I2C_INSTANCE]); Conclusion To summarize, as consumers demand more and more power efficient technology with more and more functionality, MCU product developers need to cram more functionality in small power efficient MCUs.  Relying on DMA for basic data transfers is one good way to improve performance of smaller power efficient MCUs with a single core. This can be particularly useful in applications where an MCU needs to pull information from and I2C sensor.  To do this, there are three methods of implementing an I2C master receive function in your SDK 1.3 based application. Use two DMA channels.  The first to transfer from the I2C Data register to the destination array.  A second dedicated DMA channel can be linked to write the I2C_C1 register every time the I2C_D register is serviced. Use two DMA channels.  The first to transfer from the I2C Data register to the destination array. The second DMA channel can be linked to write the I2C_C1 register only after the second to last data byte has been received. Use a single DMA channel can be set to receive two data bytes less than the total number of desired data bytes and the core (application software) can handle the reception of the last two bytes. The recommendation of this document is to implement the first or second option as these are fully automatic options requiring the least intervention by the core.
View full article