Kinetis Microcontrollers Knowledge Base

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

Kinetis Microcontrollers Knowledge Base

Discussions

Sort by:
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
The Real Time Clock (RTC) module is the right tool when we want to keep tracking the current time for our applications. For the Freedom Platform (KL25Z) the RTC module features include: 32-bit seconds counter with roll-over protection and 32-bit alarm 16-bit prescaler with compensation that can correct errors between 0.12 ppm and 3906 ppm. Register write protection. Lock register requires POR or software reset to enable write access. 1 Hz square wave output. This document describes how to implement the module configuration. Also, how to modify the hardware in order feed a 32 KHz frequency to RTC module (it is just a simple wire link).     Hardware. The RTC module needs a source clock of 32 KHz. This source is not wired on the board; hence we need to wire it. Do not be afraid of this, it is just a simple wire between PTC3 and PTC1 and the good news are that these pins are external.   PTC1 is configured as the RTC_CLKIN it means that this is the input of source clock.     PTC3 is configured as CLKOUT (several options of clock frequency can be selected in SIM_SOPT2[CLKOUTSEL] register). For this application we need to select the 32 Khz clock frequency.                         RTC configuration using Processor Expert. First of all we need to set the configurations above-mentioned in Component Inspector of CPU component. Enable RTC clock input and select PTC1 in Pin Name field. This selects PTC1 as RTC clock input. MCGIRCLK source as slow in Clock Source Settings > Clock Source Setting 0 > Internal reference clock > MCGIRCLK source. This selects the 32 KHz clock frequency. Set ERCLK32K Clock Source to RTC Clock Input in Clock Source Settings > Clock Source Setting 0 > External reference clock > ERCLK32K Clock Source. This sets the RTC_CLKIN as the 32 KHz input for RTC module. Select PTC3 as the CLKOUT pin and the CLKOUT pin output as MCGIRCLK in Internal peripherals > System Integration Module > CLKOUT pin control. With this procedure we have a frequency of 32 KHz on PTC3 and PTC1 configured as RTC clock-in source. The MCG mode configurations in this case is PEE mode: 96 MHz PLL clock, 48 MHz Core Clock and 24 MHz Bus clock.   For the RTC_LDD component the only important thing is to select the ERCKL32K as the Clock Source. The image below shows the RTC_LDD component configuration for this application.   After this you only need to Generate Processor Expert Code and write your application.  The code of this example application can be found in the attachments of the post. The application prints every second the current time.     RTC bare-metal configuration. For a non-PEx application we need to do the same configurations above. Enable the internal reference clock. MCGIRCLK is active.          MCG_C1 |= MCG_C1_IRCLKEN_MASK; Select the slow internal reference clock source.          MCG_C2 &= ~(MCG_C2_IRCS_MASK); Set PTC1 as RTC_CLKIN and select 32 KHz clock source for the RTC module.          PORTC_PCR1 |= (PORT_PCR_MUX(0x1));              SIM_SOPT1 |= SIM_SOPT1_OSC32KSEL(0b10); Set PTC3 as CLKOUT pin and selects the MCGIRCLK clock to output on the CLKOUT pin.     SIM_SOPT2 |= SIM_SOPT2_CLKOUTSEL(0b100);     PORTC_PCR3 |= (PORT_PCR_MUX(0x5));   And the RTC module configuration could be as follows (this is the basic configuration just with seconds interrupt): Enable software access and interrupts to the RTC module.     SIM_SCGC6 |= SIM_SCGC6_RTC_MASK; Clear all RTC registers.   RTC_CR = RTC_CR_SWR_MASK; RTC_CR &= ~RTC_CR_SWR_MASK;   if (RTC_SR & RTC_SR_TIF_MASK){      RTC_TSR = 0x00000000; } Set time compensation parameters. (These parameters can be different for each application) RTC_TCR = RTC_TCR_CIR(1) | RTC_TCR_TCR(0xFF); Enable time seconds interrupt for the module and enable its irq. enable_irq(INT_RTC_Seconds - 16); RTC_IER |= RTC_IER_TSIE_MASK; Enable time counter. RTC_SR |= RTC_SR_TCE_MASK; Write to Time Seconds Register. RTC_TSR = 0xFF;   After this configurations you can write your application, do not forget to add you Interrupt Service Routine to the vector table and implement an ISR code.   In the attachments you can find two zip files: PEx application and non-PEx application.   I hope this could be useful for you,   Adrián Sánchez Cano. Original Attachment has been moved to: FRDM-KL25Z-RTC-TEST.zip Original Attachment has been moved to: FRDM-KL25Z-PEx-RTC.zip
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
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
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
Porting FatFs file system to KL26 SPI SD card code 1 Abstract      Without the SDHC module, Kinetis KL series need to use the SPI interface to communicate with the SD card. Normally, when customer use the SD card, they are not only want to write and read the SD card, but also prefer to create files(eg, text file, csv file,etc.) in the SD card to record some important data. Use the file to record the data, then the data can be read easily by the PC. MCU need to use the file system to operate the files, the file system should realize the function of file creating, file deleting, file reading and writing, etc. FatFs is a generic FAT/exFAT file system module for small embedded systems. This document mainly describe how to port a FatFs file system to the KL26 SPI SD card code, SD card SPI interface hardware circuit and the SD card basic operation code. 2 FatFs file system introduction 2.1 FatFs feature Windows compatible FAT/exFAT file system. Platform independent. Easy to port. Very small footprint for program code and work area. Various configuration options to support for: Multiple volumes (physical drives and partitions). Multiple ANSI/OEM code pages including DBCS. Long file name in ANSI/OEM or Unicode. exFAT file system. RTOS envilonment. Fixed or variable sector size. Read-only, optional API, I/O buffer and etc... 2.2 FatFs file system organizations   From the above pictures, we can see that in a project with Fatfs module, there mainly 4 parts: application, Fatfs, Disk I/O layer and the Media(SD card). (1) Application, user just need to call the FatFs API function to realize the file creation, read, write and delete. (2) FatFs module, this module contains 6 important files which customer need to use, it is: diskio.c, diskio.h, ff.c, ff.h, ffconf.h, integer.h.  diskio.c and diskio.h is used to call the SD card operation function from the Disk I/O layer, user need to modify this file to match the disk I/O layer, or write the disk I/O layer match this file. ff.c,ff.h is the FatFs file system layer, it defines the API function, user don’t need to modify it. ffconf.h is the system configuration file. integer.h is the data type define file, user don’t need to modify these two files. (3) Disk I/O layer, there has mmc.c and spi.c, actually, the detail name can be defined by the user, it is not fixed. Mmc.c is used to realize the SD card function, eg, SD initialization, SD block writing and reading.  Spi.c is the MCU SPI interface file, it realize the SPI communication function, because the Kinetis series don’t have the SDHC interface, then it use the SPI interface to communicate with the SD card. (4) Media, it can be SD,MMC, USB, NAND flash, here we use the SD card. More details, please refer to FatFs Module application note. 2.3 Common API function f_mount - Register/Unregister a work area of a volume f_open - Open/Create a file f_close - Close an open file f_read - Read data f_write - Write data f_lseek - Move read/write pointer, Expand size f_truncate - Truncate size f_sync - Flush cached data More functions, please go to this link: http://elm-chan.org/fsw/ff/00index_e.html 3 SPI SD operation 3.1 Hardware       This document use the YL_KL26 as the testing board, customer also can add an external SD card circuit to the FRDM-KL26 board. The board is using the TF card, SD SPI interface circuit is:   The pin assignment in the YL-KL26 board is defined as follows: KL26 pin SPI name PTC4 SPI_CS0 PTC5 SPI_SCK PTC6 SPI_MOSI PTC7 SPI_MISO 3.2 Softwave      The test code project is based on the MDK5.1x. 3.3 SD I/O Layer 3.3.1 SD card initialization The communication speed for SD card initialization can’t exceed 400kb/s, if the speed is higher than 400kbps, user need to add the delay in the initialization code, otherwise the initialization will be failure. After the initialization is successful, user can increase the SD card communication speed. Initialization process: (1)  Initialize the SPI interface which connect to the SD card, down to low speed. (2)  Power on delay 72clks, wait for the SD card ready (3)  Go idle state, CMD0, this command will trigger the SD card to use the SPI interface. (4)  Get SD card information, CMD8, get the SD card version. (5) Active the SD card,  with CMD55+CMD41 (6) Read OCR data,CMD59. (7) Set SD card block size to 512Byte. CMD16 (8) Read CSD, get other information, CMD9 (9) Change to high speed and disable the CS uint8 MMCInit(void) {                 uint8 i = 0,k = 0,tmp = 0;                 uint16 cnt=0;                 uint8  buff[512];                                 SSP0LowSpeed();                                      // low speed                 MMCDelayUs(5000);                                                                                   for (i=0; i<0x0F; i++)                               {                    Send_Byte(0xFF);          // send 72 clocks                 }                 // Send Command CMD0 to SD/SD Card  enter idle                 do                 {                     tmp = MMCWriteCmd(CMD0,0x00,0x95);   // CMD0                      k++;                 }while ((tmp != 1) && (k < 200));                                   if(k == 0)                 {                   MMCCS(1);           //cs pullup, disconnect                   Send_Byte(0xFF);                   printf("\n SD reset fail");                   return 1;//                 }                                              //get SD card version                  tmp = MMCWriteCmd( CMD8,0x1AA,0x87 );                  printf( "SD_CMD8  return  %d........\n\n", tmp );  if(tmp == 1)// 2.0 card {          cnt=0xffff;                    do    {     MMCWriteCmd( CMD55, 0, 0xff );     tmp = MMCWriteCmd( CMD41,0x40000000, 0xff);//CMD41      cnt--;    } while ((tmp) && (cnt));                  //Get OCR information                  tmp = MMCWriteCmd(CMD58, 0, 0 );    if ( tmp != 0x00 )    {                   MMCCS(1);           //cs pullup, SD card disconnect                                 printf( "\nSD_CMD58 return  %d....\n", tmp );                   return 1;//    }      for ( i = 0; i < 4; i++ )    {     buff[ i ] = Get_Byte();    }    MMCCS(1);    printf( "OCR return: %x %x %x %x....\n\n", buff[0],buff[1],buff[2],buff[3] );      if ( buff[0] & 0x40 )    {                                  SD_Type = SD_TYPE_V2HC;      printf( "card is V2.0 SDHC.....\n\n" );    }    else {                                  SD_Type = SD_TYPE_V2;      printf( "card is V2.0.....\n\n" );    }              while(MMCWriteCmd(CMD16,512,0xff)!=0);                  MMCWriteCmd(CMD9,0,0xff);   }                 SSP0HighSpeed();                    //back to high speed                 MMCCS(1);                             return 0;                        } 3.3.2 Read one SD card block The block size is 512Byte, the read process is: Send CMD17 and wait the response Receive the start token 0XFE Receive the 512Byte data Receive 2 bytes CRC Disable the CS pin   uint8 MMCReadSingleBolck(uint32 addr,uint8 *buf) {                 uint16 i;                 uint8 sta;                 if(SD_Type!=SD_TYPE_V2HC)                 {                       addr= addr<<9;                 }                 sta = MMCWriteCmd(CMD17,addr,0x01);                 while(sta !=0)                 {                   sta = MMCWriteCmd(CMD17,addr,0x01);                 }                   while (Get_Byte() != 0xFE){;}                   if(sta == 0)                 {                   for (i=0; i<512; i++)                        {                     buf[i] = Send_Byte(0xFF);                   }                            }                 Send_Byte(0xFF);                                                                  Send_Byte(0xFF);                 MMCCS(1);                 return 0; } 3.3.3 Read multiple SD card block uint8 MMCReadMultipleBolck(uint32 addr,uint8 *buf,uint8 count) {          uint16 i;                 if(SD_Type!=SD_TYPE_V2HC)                 {                     addr= addr<<9;                 }                                                 if (MMCWriteCmd(CMD18,addr,0xFF) != 0x00)                    {                     return 1;                                          }                                 MMCCS(0);                 do                 {                     while (Send_Byte(0xFF) != 0xFE){;}                     for (i=0; i<512; i++)                                         {                         *buf++ = Send_Byte(0xFF);                     }                     Send_Byte(0xFF);                                                                                         Send_Byte(0xFF);                                 }while (--count);                 MMCCS(1);                 MMCWriteCmd(CMD12,0x00,0xFF);                   Send_Byte(0xFF);//delay                 return 0; } 3.3.4 Write one SD card block The procedure is: Send CMD24 and wait the response Receive the start token 0XFE Send the 512Byte data Send 2 bytes CRC Disable the CS pin   uint8 MMCWriteSingleBlock(uint32 addr,const uint8 *buf) {                 uint16 i,retry ;                 uint8  temp;                                 if(SD_Type!=SD_TYPE_V2HC)                 {                      addr=addr<<9 ;                 }                                              if (MMCWriteCmd(CMD24,addr,0x01) != 0x00)                         {                     return 1;                                                  }                 MMCCS(0);                 //wait SD card ready                 Send_Byte(0xFF);                          Send_Byte(0xFF);                 Send_Byte(0xFF);                 Send_Byte(0xFE);                               for (i=0; i<512; i++)                                 {                     Send_Byte(buf[i]);                 }                 //Dummy CRC                 Send_Byte(0xFF);                                                                              Send_Byte(0xFF);                 temp = Send_Byte(0xFF);                                                        temp &= 0x1F;                        if (temp != 0x05)                 {                     MMCCS(1);                     return 1;                                                                                                  }                                                 while (Send_Byte(0xFF) == 0x00)                 {                      retry++;                      if(retry>0xfffe)                     {                       MMCCS(1);                        return 1 ;                      }                 }                 MMCCS(1);                 Send_Byte(0xFF);                 return 0; } 3.3.5 Write multiple SD card block uint8 MMCReadMultipleBolck(uint32 addr,uint8 *buf,uint8 count) {     uint16 i;                 if(SD_Type!=SD_TYPE_V2HC)                 {                                   addr= addr<<9;                 }                                                 if (MMCWriteCmd(CMD18,addr,0xFF) != 0x00)                    {                     return 1;                                          }                                 MMCCS(0);                 do                 {                     while (Send_Byte(0xFF) != 0xFE)                     {                         ;                                                                                    }                                     for (i=0; i<512; i++)                                         {                         *buf++ = Send_Byte(0xFF);                     }                                     Send_Byte(0xFF);                                                                                         Send_Byte(0xFF);                                 }while (--count);                                 MMCCS(1);                 MMCWriteCmd(CMD12,0x00,0xFF);                   Send_Byte(0xFF);//delay                 return 0; } 4 FatFs file system porting 4.1 FatFs source code download Go to FatFs official website download the source code, the link is: http://elm-chan.org/fsw/ff/00index_e.html The latest version is FatFs R0.12.    Unzip it, like the following picture, just need 6 files, user can copy it to the project SPI driver folder, and create a new folder named as fatfs. 4.2 Modify diskio.c file We need to modify these functions: disk_initialize:Disk initialize disk_status     :Get the Disk status disk_read       :Read Disk block disk_write      :Write Disk block disk_ioctl       :control device character get_fattime    :Get current time 4.2.1 disk_initialize function DSTATUS disk_initialize (                 BYTE pdrv                                                 ) {                 DSTATUS stat;                    stat=MMCInit();  //SD card initialization                  if(stat == STA_NODISK)                    {                         return STA_NODISK;                     }                 else if(stat != 0)                   {                         return STA_NOINIT;                   }               else                {                      return 0;                         } } 4.2.2 disk_status  function DSTATUS disk_status (                 BYTE pdrv                 /* Physical drive nmuber to identify the drive */ ) {        if(pdrv)     {         return STA_NOINIT;      }                 return RES_OK; } 4.2.3 disk_read function DRESULT disk_read (                 BYTE pdrv,                                /* Physical drive nmuber to identify the drive */                 BYTE *buff,                               /* Data buffer to store read data */                 DWORD sector,        /* Sector address in LBA */                 UINT count                               /* Number of sectors to read */ ) {     DRESULT res;     if (pdrv || !count)     {            return RES_PARERR;      }                           if (count == 1)                  {                                 res = MMCReadSingleBolck(sector,buff);                 }                 else                           {                                 res = MMCReadMultipleBolck(sector,buff,count);                 }     if(res == 0x00)     {         return RES_OK;     }     else     {         return RES_ERROR;     } } 4.2.4 disk_write function DRESULT disk_write (                 BYTE pdrv,                                                /* Physical drive nmuber to identify the drive */                 const BYTE *buff,      /* Data to be written */                 DWORD sector,                        /* Sector address in LBA */                 UINT count                                               /* Number of sectors to write */ ) {                 DRESULT res;                   if (pdrv || !count)     {            return RES_PARERR;      }     if(count == 1)     {         res = MMCWriteSingleBlock(sector, buff);     }     else     {         res = MMCWriteMultipleBlock(sector, buff, count);     }     if(res == 0)     {         return RES_OK;     }     else     {         return RES_ERROR;     } }   4.2.5 disk_ioctl function DRESULT disk_ioctl (                 BYTE pdrv,                                /* Physical drive nmuber (0..) */                 BYTE cmd,                /* Control code */                 void *buff                /* Buffer to send/receive control data */ ) {                 DRESULT res;                 BYTE n, csd[16];                 DWORD csize;                  if (pdrv)                  {                         return RES_PARERR;                  }                 res = RES_ERROR;                 switch (cmd)                 {                     case CTRL_SYNC       : res = RES_OK; break;                     case GET_SECTOR_COUNT: /* Get number of sectors on the disk (WORD) */                                                                 if((MMCWriteCmd(0x49,0x00,0x95) == 0) && MMCCSD_CID(0x49, csd))                                                                 {                                                                 if((csd[0] >> 6) == 1) /* SDC ver 2.00 */                                                                 {                                                                 csize = csd[9] + ((WORD)csd[8] << 😎 + 1;                                                                 *(DWORD*)buff = (DWORD)csize << 10;                                                                 }                                                                 else /* MMC or SDC ver 1.XX */                                                                 {                                                                 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;                                                                 csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;                                                                 *(DWORD*)buff = (DWORD)csize << (n - 9);                                                                 }                                                                 res = RES_OK;                                                                 }                                                                 break;                     case GET_SECTOR_SIZE : /* Get sectors on the disk (WORD) */                                                                    *(WORD*)buff = 512;                                                                    res = RES_OK;                                                                    break;                     case GET_BLOCK_SIZE  :                                                             if ((MMCWriteCmd(0x49,0x00,0x95) == 0) && MMCCSD_CID(0x49, csd)) /* Read CSD */                                                        {                              *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);                                                                        res = RES_OK;                                                        }                                            break;                       default              : res = RES_PARERR; break;                 }                   return res; } 4.2.6 Get_fattime function   This function is used to get the current time, and write it in the file attribute when create, modify the files. It should associate with the RTC, this project didn’t add this function, so just write the code like this: DWORD get_fattime (void) { return 0; } 4.2.7 include SD.h file Comment usb, ATA include files, and add the user SD.h file, this is the SD card IO layer header file. #include "diskio.h"                   /* FatFs lower layer API */ //#include "usbdisk.h"              /* Example: Header file of existing USB MSD control module */ //#include "atadrive.h"            /* Example: Header file of existing ATA harddisk control module */ //#include "sdcard.h"                               /* Example: Header file of existing MMC/SDC contorl module */ #include "SD.h" /* Definitions of physical drive number for each drive */ //#define ATA                           0              /* Example: Map ATA harddisk to physical drive 0 */ //#define MMC                        1              /* Example: Map MMC/SD card to physical drive 1 */ //#define USB                          2              /* Example: Map USB MSD to physical drive 2 */ 4.3 Modify main function This project function is to create two files: Test.csv and Test.txt.  Write four items in these files: Test1, Test2, Test3, Test4. int main (void) {                 uint16 i,j;                 FATFS fs;                               FRESULT fr;                 FIL          fil;                                                            UINT bw;                 char file_name1[12]="Test.csv";                 char file_name2[12]="Test.txt";                 System_init();                 spiInit(SPI0_BASE_PTR , Master);                 fr= f_mount(&fs,file_name1,0);                 if(fr)                 {                                 printf("\nError mounting file system\r\n");                                 for(;;){}                 }                 fr = f_open(&fil, file_name1, FA_WRITE | FA_OPEN_ALWAYS);//create csv file                 if(fr)                 {                                 printf("\nError opening text file\r\n");                                 for(;;){}                 }                 fr = f_write(&fil, "Test1 ,Test2 ,Test3 ,Test4 \r\n", 29, &bw); //write data to the excel file                 if(fr)                 {                                 printf("\nError write text file\r\n");                                 for(;;){}                 }                  fr = f_close(&fil);                 if(fr)                 {                                 printf("\nError close text file\r\n");                                 for(;;){}                 }                 fr= f_mount(&fs,file_name2,0);                 if(fr)                 {                                 printf("\nError mounting file system\r\n");                                 for(;;){}                 }                              fr = f_open(&fil, file_name2, FA_WRITE | FA_OPEN_ALWAYS);//create txt file                 if(fr)                 {                                 printf("\nError opening text file\r\n");                                 for(;;){}                 }                 fr = f_write(&fil, "Test1 ,Test2 ,Test3 ,Test4 \r\n", 29, &bw); //write data to the txt file                 if(fr)                 {                                 printf("\nError write text file\r\n");                                 for(;;){}                 }                 fr = f_close(&fil);                 if(fr)                 {                                 printf("\nError close text file\r\n");                                 for(;;){}                 }            while(1)                 {                          for(i=0;i<10;i++) for(j=0;j<65535;j++);                         printf("\ntest_sd\n");//                 } } Add FatFs header files in the main.h. #include "spi.h" #include "SD.h" #include "diskio.h" #include "ff.h" 5 Test result     After download the code to the KL26 board, then insert a 8G microSD card which already format with the Fat32, press the reset button on the board, user can find the following printf log from the com port: It means the SD card is identified.      Now, take out the SD card and insert it to the PC, user will find there has two files: Test.csv and Test.txt. Open these files, data Test1, Test2, Test3, Test4 can be find in it,  it means the FatFs file system is porting successfully.
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
Hello all.   I would like to share an example project for FRDM-KL25Z board on which C90TFS Flash Driver was included to implement emulated EEPROM (Kinetis KL25 doesn’t have Flex Memory). It is based on the “NormalDemo” example project. A string of bytes is stored on the last page of the flash memory (address 0x1FC00-0x1FFFF), and then, it is overwritten with a different string.   The ZIP file also includes the “Standard Software Driver for C90TFS/FTFx Flash User’s Manual” document. For more information, please refer to Freescale website and search for “C90TFS” flash driver. Hope this will be useful for you. Best regards! /Carlos
View full article
Hi everyone! I have made a simple touch sensing demo for KL25z Freedom board for fast user friendly test using MSD bootloader (default combined application in Open SDA when you receive the Freedom - Mass Storage Device and serial port). Demo changes the brightness of red led populated on the board and communicate with FreeMaster visualization tool over embedded virtual serial port of Open SDA connection. Touch sensing application is controlled by TSS (touch sensing softwere). For more information about touch sensing and download of TSS go to www.freescale.com/tss The visualization output has 2 separate scope windows: one showing signals captured from electrodes of slider another one showing position of finger on a slider The operation is really simple, just drag and drop the attached *.s19 file into your device using MSD bootloader (as other precompiled projects for Freedom board) open the *.pmp file that is associated with FreeMASTER, choose the correct COM port at speed of 38400 kbps and start communication The demo was made in CodeWarrior 10.4 using TSS library 3.0.1 in Processor Expert tool, source code can be provided if there will be an interest. There is no need to configure MAP file for FreeMaster communication, application uses so called TSA table - it is position independent this way. If you are not familiar with FreeMASTER or not have it installed in your PC - go to www.freescale.com/freemaster to read more and download the free installer, install it and you are good to run the demo. There are two independent snapshots below, showing the response to my finger movement along the slider Enjoy! and keep in touch
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
With the merger of NXP and Freescale, the NXP USB VID/PID program, which was previously deployed on LPC Microcontrollers, has been extended to Kinetis Microcontrollers and i.MX Application Processors. The USB VID/PID Program enables NXP customers without USB-IF membership to obtain free PIDs under the NXP VID. What is USB VID/PID Program? The NXP USB VID program will allow users to apply for the NXP VID and get up to 3 FREE PIDs. For more details, please review the application form and associated FAQ below. Steps to apply for the NXP USB VID/PID Program Step 1: Fill the application form with all relevant details including contact information. Step 2: NXP will review the application and if approved, will issue you the PIDs within 4 weeks FAQ for the USB VID/PID Program Can I use this VID for any microcontroller in the NXP portfolio? >> No. This program is intended only for the Cortex M based series of LPC Microcontrollers and Kinetis Microcontrollers, and Cortex A based series of i.MX Application Processors. What are the benefits of using the NXP VID/PID Program? >> USB-IF membership not required >> Useful for low volume production runs that do not exceed 10,000 units >> Quick time to market Can I use the NXP VID and issued PID/s for USB certification? >> You may submit a product using the NXP VID and issued PID/s for compliance testing to qualify to use the Certified USB logo in conjunction with the product, but you must provide written authorization to use the VID from NXP at the time of registration of your product for USB certification. Additionally, subject to prior approval by USB-IF, you can use the NXP VID and assigned PID/s for the purpose of verifying or enabling interoperability. What are the drawbacks of using the NXP VID/PID program? >> Production run cannot exceed 10,000 units. See NXP VID application for more details. >> Up to 3 PIDs can be issued from NXP per customer. If more than 3 PIDs are needed, you have to get your own VID from usb.org: http://www.usb.org/developers/vendor/ >> The USB integrators list is only visible to people who are members of USB-IF. NXP has full control on selecting which products will be visible on the USB integrators list. How do I get the VID if I don't use NXP’s VID? >> You can get your own VID from usb.org. Please visit http://www.usb.org/developers/vendor/ Do I also get the license to use the USB-IF’s trademarked and licensed logo if I use the NXP VID? >> No. No other privileges are provided other than those listed in the NXP legal agreement. If you wish to use USB-IF’s trademarked and licensed USB logo, please follow the below steps:                 1. The company must be a USB vendor (i.e. obtain a USB vendor ID).                 2. The company must execute the USB-IF Trademark License Agreement.                 3. The product bearing the logo must successfully pass USB-IF Compliance Testing and appear on the Integrators List under that company’s name. Can I submit my product for compliance testing using the NXP VID and assigned PIDs? >> Yes, you would be able to submit your products for USB-IF certification by using the NXP VID and assigned PID. However, if the product passes the compliance test and gets certified, it will be listed under “NXP Semiconductors” in the Integrators list. Also, you will not have access to use any of the USB-IF trademarked and licensed USB logos. How long does it take to obtain the PID from NXP? >> It can take up to 4 weeks to get the PIDs from NXP once the application is submitted. Are there any restrictions on the types of devices that can be developed using the NXP issued PIDs? >> This service requireds the USB microcontroller to be NXP products. Can I choose/request for a specific PID for my application? >> No. NXP will not be able to accommodate such requests.
View full article
Latest version of the AN2295 universal bootloader includes support for IAR 7.6 IDE. - added support for Kinetis E MCUs - Kinetis K,L,M,E,W,V support
View full article
        在我们嵌入式工程应用中,中断作为最常用的异步手段是必不可少的,而且在一个应用程序中,一个中断往往是不够用的,多个中断混合使用甚至多级中断嵌套也经常会使用到,而这样就涉及到一个中断优先级的问题。         以我们最熟悉的Cortex-M系列为例,我们知道ARM从Cortex-M系列开始引入了NVIC的概念(Nested Vectors Interrupts Controller),即嵌套向量中断控制器,以它为核心通过一张中断向量表来控制系统中断功能,NVIC可以提供以下几个功能: 1)可嵌套中断支持; 2)向量中断支持; 3)动态优先级调整支持; 4)中断可屏蔽。         抛开其他不谈,这里我们只说说中断优先级的问题。我们知道NVIC的核心工作原理即是对一张中断向量表的维护上,其中M4最多支持240+16个中断向量,M0+则最多支持32+16个中断向量,而这些中断向量默认的优先级则是向量号越小的优先级越高,即从小到大,优先级是递减的。但是我们肯定不会满足于默认的状态(人往往不满足于约束,换句俗话说就是不喜欢按套路出牌,呵呵),而NVIC则恰恰提供了这种灵活性,即支持动态优先级调整,无论是M0+还是M4除了3个中断向量之外(复位、NMI和HardFault,他们的中断优先级为负数,它们3个的优先级是最高的且不可更改),其他中断向量都是可以动态调整的。         不过需要注意的是,中断向量表的前16个为内核级中断,之后的为外部中断,而内核级中断和外部中断的优先级则是由两套不同的寄存器组来控制的,其中内核级中断由SCB_SHPRx寄存器来控制(M0+为SCB_SHPR[2:3],M4为SCB_SHPR[1:3]),外部中断则由NVIC_IPRx来控制(M0+为NVIC_IPR[0:7],M4为NVIC_IPR[0:59]),如下图所示: M0+中断优先级寄存器: M4中断优先级寄存器:         其中M4所支持的动态优先级范围为0~15(8位中只有高四位[7:4]才有效),而M0+所支持的动态优先级范围则为0~3(8位中只有高两位[7:6]才有效),而且秉承着号越小优先级越高的原则(0最高,15或3为最小),同时也间接解释了为什么复位(-3)、NMI(-2)和HardFault(-1)优先级最高的原因,很简单,人家都是负的了,谁还能比他们高,呵呵,而且这三位中复位优先级最高,NMI其次,HardFault最低(这个最低仅限于这三者)。 下面给出个ARM CMSIS库中关于M0+和M4中断优先级设置的API函数NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)实现供大家来参考: M0+: NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) {   if(IRQn < 0) {     SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |         (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }  /* set Priority for Cortex-M  System Interrupts */   else {     NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |         (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }   /* set Priority for device specific Interrupts  */ } M4: void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) {   if(IRQn < 0) {     SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M  System Interrupts */   else {     NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */ }
View full article
Background: NXP SC18IS602B I2C bus to SPI bridge chip is using TSSOP16 package, which is 16 leads; 0.65 mm pitch; 5 mm x 4.4 mm x 1.1 mm body. Customer requires to use a smaller package to emulate the SC18IS602B function. Kinetis L series MKL03Z16VFK4R product uses QFN24 package with 4 mm x 4 mm x 0.58 mm body. Demo Overview The I2C to SPI Bridge demo provides a replacement solution demo of SC18IS602B chip. The demo is based on FRDM-KL03Z board using I2C0 module as I2C slave and SPI0 module as SPI master. Provided data buffer size is 400bytes. The demo software is based on KSDK V2.0 for FRDM-KL03Z software. I2C slave interface: Pin number                 Function              FRDM-KL03Z jumper PTB3                          I2C0_SCL           J2-10 PTB4                          I2C0_SDA           J2-9   SPI master interface: Pin number                 Function              FRDM-KL03Z jumper PTA5                           SPI0_SS             J2_3 PTA6                           SPI0_MISO         J2_5 PTA7                           SPI0_MOSI         J2_4 PTB0                           SPI0_SCK           J2_6   INT pin (indicates if I2C to SPI Bridge allows i2c master start a new i2c transfer, low is active) Pin number                 Function              FRDM-KL03Z jumper PTB11                        GPIO output         J2_2   Connect I2C master with FRDM-KL03Z I2C slave interface and connect SPI slave with FRDM-KL03Z SPI master interface; Connect FRDM-KL03Z GND to I2C master and SPI slave before add power to those boards.  Below is the hardware platform connection way: I2C to SPI Bridge Demo Function For the KL03 chip with one SPI0_PCS0 chip select pin, I2C to SPI Bridge demo only supports function ID 0x01 as SPI write command. For example: if i2c master want to write 8bytes (0x21,0x22...0x28) to SPI slave, the i2c master needs to send below data to FRDM-KL03Z board:   [START] + [I2C Slave address+/W] + [0x01](Function ID) + [0x21](data 1) + [0x22](data 2) + ... +[0x28](data 😎 + [STOP]     I2C to SPI bridge demo supports Function ID 0xF0 to configure SPI interface: There provides four SPI baud rate: 6Mbps/3Mbps/1.5Mbps/1Mbps. More detailed info, please check below picture (picture abstracted from SC18IS602B datasheet): For example: customer could configure SPI baud rate to 3Mbps with send below data to FRDM-KL03Z board:        [START] + [I2C Slave address+/W] + [0Xf0](Function ID) + [0x01](data 1) + [STOP] Hardware Platform The demo is based on FRDM-KL03Z board, using internal IRC48M clock as system and bus clock source. There doesn’t need external clock source. Toolchain supported - IAR embedded Workbench 7.60.1  (Tested) - Keil MDK 5.18a - GCC ARM Embedded 2015-4.9-q3 - Kinetis Development Studio IDE 3.2.0 Running the Demo Connect a USB cable between the host PC and the USB port on the target board. Open a serial terminal with the following settings:     - 9600 baud rate     - 8 data bits     - No parity     - One stop bit     - No flow control Download the program to the target board. I2C master start to configure SPI interface      I2C to SPI bridge board I2C address is 0x7E. I2C master write data to SPI slave    I2C master write 10bytes to SPI slave, it will send 11bytes (includes one function ID 0x01). The first data is 0xAA and the last data is 0x22.    After I2C to SPI Bridge receive the data, it will send 10bytes to SPI slave.        I2C to SPI Bridge receive 10 bytes     I2C to SPI Bridge send 10bytes to SPI slave I2C master read data from SPI slave    I2C master read 10bytes(0x10 to 0x19) from SPI slave need to write data to SPI slave at first, then read data from I2C to SPI bridge data buffer directly.    Here just shows read 10bytes from I2C to SPI bridge data buffer. Attached I2C to SPI Bridge demo software default location is: ..\SDK_2.0_FRDM-KL03Z\boards\frdmkl03z\user_apps\i2c_to_spi
View full article
    以DMA方式通过UART发送数据应该是工程应用中很常用的一种方式了,尤其是在需要频繁发送数据或者数据包长度较大的场合,如果使用传统的UART查询或者中断方式发送和接收数据,对CPU资源的占用将是极大的浪费,带操作系统的应用还好些,如果是纯粹的前后台程序有时不能容忍的,所以DMA方式是很恰当的选择。而本篇以Kinetis L系列为例介绍一下以DMA方式通过UART端口发送长数据包,当然不同于K系列复杂强大的eDMA功能,L系列的DMA模块配置起来还是比较简单的。 测试平台:IAR6.7 + KL26 FRDM 测试代码:FRDM-KL26Z_SC\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\build\iar\uart0_dma        其实KL26的官方sample code中是自带uart0_dma例程的,但是实现的功能只是将UART口接收到的每一个字节的数据通过DMA方式再发送出去(即环形缓冲),这样用来作为一个功能演示的demo是可以,但是往往我们需要的是将某缓冲区的数据以DMA方式发送出去或者将接收到的数据以DMA方式写到某缓冲区这样的功能,为此我们就需要在原有的例程上进行修改从而达到我们的应用目的,这里给出几点需要修改的地方,并做了相关注释(整个工程见最后附件): 1)定义待发送缓冲区: /* array to be sended */ uint8 testdata[]={"\nFreescale Kinetis KL26\n"}; 2)设置DMA源地址: #define DMA0_DESTINATION  0x4006A007    /* the memory adress of UART0_D register */ #define DMA0_SOURCE_ADDR  (uint32)testdata    /* define the source data array address */ 3) 在DMA0_init()函数中修改发送数据包的长度: DMA_SAR0 = DMA0_SOURCE_ADDR;    //Set source address to UART0_D REG DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(sizeof(testdata));    //Set BCR to know how many bytes to transfer DMA_DCR0 &= ~(DMA_DCR_SSIZE_MASK | DMA_DCR_DSIZE_MASK);    //Clear source size and destination size fields 4)添加源地址自动加1功能,因为之前的环形缓冲方式只是单字节数据,所以不需要源地址递增,但是由于我们这次需要发送整个数据包,所以这里我们就需要将源地址递增功能打开,而具体递增1,2还是4则取决于发送数据的最小单位(8bit,16bit or 32bit): /* Set DMA as follows: Source size is 8-bit size Destination size is 8-bit size Cycle steal mode External requests are enabled source address increments 1 automatically */ DMA_DCR0 |= (DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1) | DMA_DCR_CS_MASK | DMA_DCR_ERQ_MASK | DMA_DCR_EINT_MASK | DMA_DCR_SINC_MASK); 5)配置DMAMUX通道为UART0 TX即发送通道(通道号为3),因为我们需要的是UART0_TX触发DMA传送: DMA_DAR0 = DMA0_DESTINATION;    //Set source address to UART0_D REG DMAMUX0_CHCFG0 = DMAMUX_CHCFG_SOURCE(3);    //Select UART0 TX as channel source DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK;    //Enable the DMA MUX channel 6)在UART0_DMA_init()函数中修改UART0发送缓冲区为空时即触发DMA发送: void UART0_DMA_init(void) { UART0_C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);  //Disable UART0 UART0_C5 |= UART0_C5_TDMAE_MASK;                      // Turn on DMA request(Transmit) for UART0 UART0_C2 |= (UART0_C2_TE_MASK | UART0_C2_RE_MASK);  //Enable UART0 } 7)在DMA发送完成中断服务函数中禁掉DMA通道,实现单次发送,即每个数据包发送完成之后即停止发送,否则不禁掉的话会一直触发DMA发送,造成串口堵塞: void DMA0_IRQHandler(void) {  /* Create pointer & variable for reading DMA_DSR register */ volatile uint32_t* dma_dsr_bcr0_reg = &DMA_DSR_BCR0; uint32_t dma_dsr_bcr0_val = *dma_dsr_bcr0_reg; if (((dma_dsr_bcr0_val & DMA_DSR_BCR_DONE_MASK) == DMA_DSR_BCR_DONE_MASK)      | ((dma_dsr_bcr0_val & DMA_DSR_BCR_BES_MASK) == DMA_DSR_BCR_BES_MASK)      | ((dma_dsr_bcr0_val & DMA_DSR_BCR_BED_MASK) == DMA_DSR_BCR_BED_MASK)      | ((dma_dsr_bcr0_val & DMA_DSR_BCR_CE_MASK) == DMA_DSR_BCR_CE_MASK)) { DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;                //Clear Done bit DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(sizeof(testdata));      //Reset BCR dma0_done = 1; } /* once the array complete the transfer, then disable the DMA channel.*/ DMAMUX0_CHCFG0 &= ~DMAMUX_CHCFG_ENBL_MASK; }        将上述代码做完相应修改即可实现单次将内存缓冲区数据以DMA方式通过UART0发送出去,效果如下。此外,如果想周期性触发或者条件性触发,则只需再相应位置添加“DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK;”这句代码即可打开通道,然后立即会触发UART0_TX发送数据,然后待数据包发送完之后再次停止等待下次使能。 另外,关于DMA的传输速度的话,因为其独立占用一条自己的总线,其搬运时钟为系统时钟(即coreclock/Systemclock),相比于总线上的传输速度,本例程中整个数据包的发送时间主要是取决于UART串口的波特率*数据包长度。 附件为修改好后的完整工程:
View full article
Problem Analysis and solutions for booting from ROM BOOTLOADER in KL series 1 Abstract      When customer use the kinetis chip KL43, KL27 and KL17 which flash size is above 128K, they have found a problem that if the code boot from the ROM instead of the flash, the application code about the LPUART and I2C will run in abnormal state, especially when use PTA1 as the  LPUART receive pin, UART transmit function has no problem, but when the PTA1 receive the UART data, the code will run to the abnormal area and can’t return back, the code will be crash. This problem only happens on booting from the ROM and the uart and i2c peripheral are enabled in BCA 0x3d0 address, uart peripheral enablement in BCA area will influence the application PTA1 uart receive, i2c peripheral enablement in BCA area will influence the i2c0 module in the application code. If booting from the flash or booting from ROM but the uart and I2C peripheral are disabled in the BCA 0x3d0 address, everything is working ok in the application code.      This document will take the UART problem as an example, give details of the problem reproduction, testing, analysis and the solutions. The I2C problem is the same when booting from the ROM bootloader. 2 Problem reproduction and analysis  Testing preparation: IDE: KDS 和IAR Hardware: FRDM-KL43 Software: 3.0 and KSDK2.0_FRDM-KL43      We mainly reproduce the uart receive problem in two ways: new KDS PE project based on KSDK1.3.0 and official newest sample code package KSDK2.0_FRDM-KL43. 2.1 Problem reproduction in new creating kds project Because the KSDK2.0 still doesn’t support the PE function in the KDS IDE, so we use the KSDK1.3.0 as the PE KSDK to create the new KDS project. 2.1.1 Create KDS KL43 project The new KDS PE project creating is very simple, here just describe the important points which is relate to the UART problem after booting from the ROM. At first create a new KDS PE project which is based on KSDK1.3.0, and choose the chip as MKL43Z256VLH4, select the MCG mode as HIRC, and configure core clock to 48Mhz, bus clock to 24Mhz. Then add the uart module fls_debug_console for testing, because the FRDM_KL43 is using PTA1 and PTA2, the console module can be configured like the following picture, after the module is configured, press the code generation button to generate the project code. Then add the simple code in file main.c main function for testing: char a; for(;;) {                 PRINTF(" test!\n");                 a= GETCHAR();                 PUTCHAR(a);               } The code function is: printf the “test!” to the COM port in the PC, then wait the uart data, if receive the data, then printf the received data back and run this loop function again.   2.1.2 Add the BCA area    From the KL43 reference manual, we can get that, BCA start address is 0X3C0:     The KDS newly created project didn’t contain the BCA area in the link file, so we need to add this area in the link file and add the BCA data in the start file by ourselves. 2.1.2.1 Divide the BCA flash are in .ld file Add the following code to define the BCA start flash address and the flash size in the ProcessorExpert.ld memory area: m_bca                 (RX)  : ORIGIN = 0x000003C0, LENGTH = 0x00000040 Then add this code in the SECTIONS area:   .bca :            {              . = ALIGN(4);              KEEP(*(.bca)) /* Bootloader Configuration Area (BCA) */              . = ALIGN(4);            } > m_bca At last, the ld file is like this: For the ld file protection, we can change the ld file properties to read-only, then this file won’t be changed to the initial one after building. 2.1.2.2 Add the BCA data in the start file      After add the BCA flash area divide code, we still need to define the BCA data in the start file:    /* BCA Area */     .section .bca, "a"                 .ascii "kcfg"                            // [00:03] tag                 .long 0xFFFFFFFF // [07:04] crcStartAddress                 .long 0xFFFFFFFF // [0B:08] crcByteCount                 .long 0xFFFFFFFF // [0F:0C] crcExpectedValue                 .byte 0x03                                             // [10] enabledPeripherals  I2C and UART                 .byte 0xFF                                              // [11] i2cSlaveAddress                 .short 3000                           // [13:12] peripheralDetectionTimeout (milliseconds)                 .short 0xFFFF                        // [15:14] usbVid                 .short 0xFFFF                        // [17:16] usbPid                 .long 0xFFFFFFFF  // [1B:18] usbStringsPointer                 .byte 0xFF                                              // [1C] clockFlags                 .byte 0xFF                                              // [1D] clockDivider                 .byte 0xFF                                              // [1E] bootFlags                 .byte 0xFF                                              // [1F] reserved*/    More details, please refer to this picture:       So far, we have create the FRDM-KL43 test project which contains the BCA area, and boot from the ROM that can be modified in the flash address 0X40D, bit 6-7 in 0X40D is the BOOTSRC_SEL bits, 00 boot from flash, 10 and 11 boot from ROM, more details about the FOPT, please refer to Table 6-2. Flash Option Register (FTFA_FOPT) definition in reference manual.     2.1.3 Test result and analysis       Now, list the test result after booting from ROM or flash, and boot from ROM but enable the peripherals. Boot from: ROM peripheral Test Result Flash XX OK ROM 0XFF, enable all NO, UART can’t receive 0X08, enable USB Yes, UART can receive 0X04, enable SPI Yes, UART can receive 0X02, enable I2C Yes, UART can receive 0X01, enable LPUART NO, UART can’t receive      From the test result, we can reproduce the problem. The UART receive problem just happens on booting from ROM and the LPUART is enabled, when we run it with debugger, and test it step by step, we can find after the PTA1 have received the data, the code will run to the abnormal area. Note: when debug this code, please choose the JLINK as the debugger, because the P&E tool will protect the FOPT area automatically in the KDS IDE when do debugging, the code will still run from flash, so if customer use the P&E tool, they will found the PTA1 still can receive the data, this is not the real result, but the JLINK won’t protect FOPT area in the KDS IDE, it can reflect the real result.      After using the JLINK as the debugger, and we have found after PTA1 getting data or pulling low, the code will enter to the abnormal area like this:      We can get that the code run to the defaultISR, and display with USB_IRQHander, but this is not really the USB_IRQHander, just caused by the PC abnormal. Normally, it is caused by the missing of interrupt service function.       Now, we test the NVIC data to check which module interrupt caused this, the following picture is the result by enabling the LPUART and I2C peripheral in the ROM BCA area. We can find, even we didn’t do the cpu and peripheral initialization after booting from ROM, there still have peripheral be enabled, what the interrupt is enabled? From the definitive guide to the ARM Cortex-M0.pdf: NVIC_ISER = 0x40000100, Vector46=IRQ30 and vector24=IRQ8 is enabled, it should be not disabled after booting from the ROM. Now check the KL43 reference manual, Table 3-2. Interrupt vector assignments, we can get that the I2C0 and PORTA interrupt is enabled. Checking the PORTA register before do the cpu and peripheral initialization, PTA1 is enabled the port interrupt, and choose Flag and Interrupt on falling-edge.     This can tell us why the PTA1 pin have the problem of uart receive data or give a falling edge in PTA1 will run abnormal, because in default, even we configure the PTA1 as the uart receive function, but the code didn’t clear IRQ and NVIC register, when the signal happens on PTA1 pin, it will caused the PORTA interrupt, but we didn’t add the PORTA interrupt ISR function, it is also not useful to us, then PC don’t know where to go, so it will run abnormal, enter the defaultISR, and can’t recover. If you have interest, you can add the PORTA_IRQHandler function, you will find the code will run to this function. 2.2 Problem reproduction in KSDK2.0 IAR project  Test project: SDK_2.0_FRDM-KL43Z\boards\frdmkl43z\demo_apps\hello_world  Test the official project just to make sure, it is really the chip hardware function, not only the problem from new generated code in KDS.   Because the IAR IDE will protect the 0X400 area, then if we want to modify the FOPT, we need to modify the .board, add –enable_config_write at first.    Then modify the FOPT in startup_MKL43Z.s: __FlashConfig         DCD 0xFFFFFFFF         DCD 0xFFFFFFFF         DCD 0xFFFFFFFF         DCD 0xFFFFFFFE   ; 0xFFFF3FFE   __FlashConfig_End   Because the BCA peripheral area is in default as 0XFF, it enables all the peripheral, we don’t need to define the BCA area independently.  For getting the real test result, we add the NVIC and PORTA_PCR1 register printf code in the main function,    PRINTF("PORTA_PCR1=%X \n", PORTA->PCR[1]);    PRINTF("NVIC=%X \n", NVIC->ICER[0U]); And download the modified KSDK sample code to the chip, after testing, we get this result: hello world. PORTA_PCR1=A0205 NVIC=40000100 It is the same result as the new created project after booting from the ROM, PORTA interrupt and I2C interrupt is enabled, and it caused the PTA1 receive data problem.  3 Solutions and test result 3.1 Solutions      From the Chapter 2 testing and analysis, we can get that UART receive problem is caused by the PORT interrupt and NVIC is enabled after booting from the ROM, this should be caused by exiting the ROM, the ROM forget to disable it. We also can find some descriptions from the KL43 reference manual page 211: So, if customer want to solve this problem, to avoid the application enter to the abnormal area, we can disable the NVIC in the application code like this, the I2C NVIC is the same:     NVIC_DisableIRQ(8);//disable I2C0 interrupt     NVIC_DisableIRQ(30); //disable PTA interrupt 3.2 Test result   From the test result after adding the NVIC I2C and PORTA disable code, we can get the uart can works ok, if you have interest to test, the I2C will also work ok. 4 Conclusion When customer use the kinetis chip KL43, KL27 and KL17 which flash size is above 128K, and want to boot from the ROM and enable the LPUART and I2C in BCA area, please add the NVIC I2C(IRQ8) and PORTA(IRQ30) disable code in the application code:     NVIC_DisableIRQ(8);//disable I2C0 interrupt     NVIC_DisableIRQ(30); //disable PTA interrupt So far, I just find KL43, KL27 and KL17 which flash size is above 128K have this problem, other kinetis chip which have ROM bootloader don’t have this problem.
View full article
When using ADCs it is not enough to just configure the module, add a clock signal, apply the Nyquist criteria and hope for the best, because normally that is just not enough. Even if we use the best software configuration, sampling rate, conversion time, etc; we might end up with noisy conversions, and worst of all a low ENOB figure which sums up in a lousy, low resolution ADC application. To complement the software end you need to follow some basic hardware design rules, some of them might seem logical, other might even weird or excessive however they are the key to a successful conversion, I took the time to compile a short list of effective design best practices trying to cover the basics of ADC design. If you think I missed something feel free to comment and ask for more information. Ground Isolation Because ground is the power return for all digital circuits and analog circuits, one of the most basic design philosophies is to isolate digital and analog grounds. If the grounds are not isolated, the return from the analog circuitry will flow through the analog ground impedance and the digital ground current will flow through the analog ground, usually the digital ground current is typically much greater than the analog ground current.  As the frequency of digital circuits increases, the noise generated on the ground increases dramatically. CMOS logic families are of the saturating type; this means the logic transitions cause large transient currents on the power supply and ground. CMOS outputs connect the power to ground through a low impedance channel during the logic transitions. Digital logic waveforms are rectangular waves which imply many higher frequency harmonic components are induced by high speed transmission lines and clock signals.                              Figure 1: Typical mixed signal circuit grounding                              Figure 2: Isolated mixed signal circuit grounding Inductive decoupling Another potential problem is the coupling of signal from one circuit to another via mutual inductance and it does not matter if you think the signals are too weak to have a real effect, the amount of coupling will depend on the strength of the interference, the mutual inductance, the area enclosed by the signal loop (which is basically an antenna), and the frequency. It will also depend primarily on the physical proximity of the loops, as well as the permeability of the material. This inductive coupling is also known as crosstalk in data lines.                               Figure 3: Coupling induced noise It may seem logical to use a single trace as the return path for the two sources (dotted lines). However, this would cause the return currents for both signals to flow through the same impedance, in addition; it will maximize the area of the interference loops and increase the mutual inductance by moving the loops close together. This will increase the mutual noise inductance and the coupling between the circuits. Routing the traces in the manner shown below minimizes the area enclosed by the loops and separates the return paths, thus separating the circuits and, in turn, minimizing the mutual noise inductance.                               Figure 4: Inductance decoupling layout Power supply decoupling The idea after power decoupling is to create a low noise environment for the analog circuitry to operate. In any given circuit the power supply pin is really in series with the output, therefore, any high frequency energy on the power line will couple to the output directly, which makes it necessary to keep this high frequency energy from entering the analog circuitry. This is done by using a small capacitor to short the high frequency signals away from the chip to the circuit’s ground line. A disadvantage of high frequency decoupling is it makes a circuit more prone to low frequency noise however it is easily solved by adding a larger capacitor. Optimal power supply decoupling A large electrolytic capacitor (10 μF – 100 μF) no more than 2 in. away from the chip. A small capacitor (0.01 μF – 0.1 μF) as close to the power pins of the chip as possible. A small ferrite bead in series with the supply pin (Optional).                               Figure 5: Power supply decoupling layout Treat signal lines as transmission lines Although signal coupling can be minimized it cannot be avoided, the best approach to effectively counteract its effects on signal lines is to channel it into a conductor of our choice, in this case the circuit’s ground is the best choice to channel the effects of inductive coupling; we can accomplish this by routing ground lines along signal lines as close as manufacturing capabilities allow. An very effective way to accomplish this is routing signals in triplets, these works for both digital and analog signals.The advantages of doing so are an improved immunity not only to inductive coupling but also immunity to external noise. Optimal routing: Routing in “triplets” (S-G-S) provide good signal coupling with relatively low impact on routing density Ground trace needs to be connected to the ground pins on the source and destination devices for the signal traces Spacing should be as close as manufacturing will allow                               Figure 6: Transmission line routing Signal acquisition circuit To improve noise immunity an external RC acquisition circuit can be added to the ADC input, it consists of a resistor in series with the ADC input and a capacitor going from the input to the circuit’s ground as the figure below shows:                                                             Figure 7: ADC with an external acquisition circuit The external RC circuit values depend on the internal characteristics and configuration of the ADC you use, such as the availability of an internal gain amplifier or the ADC’s architecture; the equation and circuit shown here represents a simplified form of ADC used in Freescale devices. The equivalent sampling resistance RSH is represented by total serial resistance connected between sampling capacitance and analog input pin (sampling switch, multiplexor switches etc.). The sampling capacitance CSH is represented by total parallel capacitance. For example in a case of Freescale SAR ADC equivalent sampling capacitance contains bank of capacitances. The equation shown how to calculate the value of the input resistor based on the values of both the input and sample and hold circuit. It must be noted the mentioned figures could have an alternate designation in any given datasheet; the ones mentioned here are specific to Kinetis devices: TAQ=      Acquisition time (.5/ADC clock) CIN=       Input capacitance (33pF min) CSH=      Sample & Hold circuit capacitance ( CDAIN in datasheet) VIN=       Input voltage level VCSH0= Initial voltage across S&H circuit (0V) VSFR=    Full scale voltage (VDDA) N=           bit resolution Note:  Special care must be taken when performing the calculation since a deviation from the correct values will result in a significant conversion error due to signal distortion.
View full article
The SPI bus has the capability of addressing multiple slave devices by a single master. The Kinetis L series of devices feature either an 8-bit or 16-bit capable SPI module; however, there is only one dedicated CS/SS signal per instance of the module. Of course this signal is muxed to a few pin locations on the device. Unfortunately, there are not that many pins with the CS/SS muxing and they are most likely they are not near to each other physically. A solution to this issue is to use GPIO as CS/SS lines. This way you can take advantage of the SPI bus protocol and the Kinetis L series IOPORT interface (also known as FGPIO on Kinetis L). The Cortex-M0+ allows accesses to the IOPORT to occur in parallel with any instruction fetches; therefore, these accesses will complete in a single cycle. Core vs. SPI I'm sure many who have tried to use GPIO as CS/SS have written code similar to this pseudo code, I know I have: while(1) {      set_cs_low;      send_byte;      set_cs_high; } Logically this makes sense, but on an oscilloscope you will see the GPIO CS/SS line toggling at irregular intervals and out of sync with the SPI transfers. This is due to the nature of the 'send_byte' function or instruction. Simply transmitting a data packet will not prevent the core from waiting for the transmission to complete. The core will move on from writing data to the SPI data register, and execute the next instruction. If you have a core operating at 48 MHz and you are performing, at most depending on instance, 24 MHz SPI transfers the core will always move onto the next instruction before the data has left the module. The code must either implement a delay or wait for the transmission to complete. Incorporating an accurate delay can be tricky and can be interrupted by any interrupts occurring during the delay process. A more robust solution is to wait for the transmission to complete. However, there appears to be no Transmit Complete Flag (TCF) in the L-Series SPI module. The Solution Fortunately, there is a way to wait for transmit complete. Software must wait for the SPI read buffer full flag (SPRF) to be set in the SPI status register (SPIx_S) after writing data to the SPI data register (SPIx_D) . When the SPRF bit is set, software must read the SPIx_D. This procedure will ensure that the core does not move onto GPIO toggling, or other instructions, until the data has left the SPI module. The following function demonstrates how to write the above procedure in C using SPI0 and PTD0 as the CS/SS line: uint8_t SPI_send(uint8_t spiWrite) {     uint8_t spiRead;                        //Variable for storing SPI data     FGPIOD_PCOR |= (1 << 0);                //Toggle CS/SS line low     while(!(SPI0_S & SPI_S_SPTEF_MASK))     {         __asm("NOP");     }                                       //Wait for SPI transmit empty flag to set     SPI0_D = spiWrite;                            //Write data to SPI     while(!(SPI0_S & SPI_S_SPRF_MASK))     {         __asm("NOP");     }                                       //Wait for receive flag to set     spiRead = SPI0_D;                       //Read the SPI data register     FGPIOD_PSOR |= (1 << 0);                //Toggle CS/SS line high     return spiRead; } Please note that the GPIO CS/SS toggling need not be in the function. It should work just as well if the GPIO CS/SS toggles occur before and after the function is call, just remove the FGPIO instructions from the function and place them outside. I hope this document proves useful to those of you designing multiple slave SPI buses around Kinetis L series parts.
View full article