Kinetis Microcontrollers Knowledge Base

cancel
Showing results for 
Search instead for 
Did you mean: 

Kinetis Microcontrollers Knowledge Base

Discussions

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
The following document contains a list of documents , questions and discussions that are relevant in the community based on the amount of views they are receiving each month. If you are having a problem, doubt or getting started in Kinetis processors or MCUXpresso, you should check the following links to see if your doubt have been already solved in the following documents and discussions. MCUXpresso MCUXpresso Supported Devices Table FAQ: MCUXpresso Software and Tools  Getting Started with MCUXpresso and FRDM-K64F  Generating a downloadable MCUXpresso SDK v.2 package  Quick Start Guide – Using MCUXpresso SDK with PINs&amp;CLOCKs Config Tools  Moving to MCUXpresso IDE from Kinetis Design Studio Kinetis Microcontrollers Guides and examples Using RTC module on FRDM-KL25Z  Baremetal code examples using FRDM-K64F Using IAR EWARM to program flash configuration field Understanding FlexIO  Kinetis K80 FAQ How To: Secure e-mail client (SMTP + SSL) with KSDK1.3 + WolfSSL for FRDM-K64F  Kinetis Bootloader to Update Multiple Devices in a Network - for Cortex-M0+  PIT- ADC- DMA Example for FRDM-KL25z, FRDM-K64F, TWR-K60D100 and TWR-K70  USB tethering host (RNDIS protocol) implementation for Kinetis - How to use your cellphone to provide internet connectivity for your Freedom Board using KSDK Write / read the internal flash Tracking down Hard Faults  How to create chain of pbuf's to be sent? Send data using UDP.  Kinetis Boot Loader for SREC UART, SD Card and USB-MSD loading  USB VID/PID numbers for small manufacturers and such like  Open SDA and FreeMaster OpenSDAv2  Freedom OpenSDA Firmware Issues Reported on Windows 10 Let´s start with FreeMASTER!  The Kinetis Design Studio IDE (KDS IDE) is no longer being actively developed and is not recommended for new designs. The   MCUXpresso   IDE has now replaced the Kinetis Design Studio IDE as the recommended software development toolchain for NXP’s Kinetis, LPC and i.MX   RT Cortex-M based devices. However, this documents continue to receive considerable amount of views in 2019 which means it could be useful to some people. Kinetis Design Studio New Kinetis Design Studio v3.2.0 available Using Kinetis Design Studio v3.x with Kinetis SDK v2.0  GDB Debugging with Kinetis Design Studio  KDS Debug Configurations (OpenOCD, P&amp;E, Segger) How to use printf() to print string to Console and UART in KDS2.0  Kinetis Design Studio - enabling C++ in KSDK projects  Using MK20DX256xxx7 with KDS and KSDK  Kinetis SDK Kinetis SDK FAQ  Introducing Kinetis SDK v2  How to: install KSDK 2.0  Writing my first KSDK1.2 Application in KDS3.0 - Hello World and Toggle LED with GPIO Interrupt 
View full article
The DOC introduces the nano-edge placement  feature for KV4x family, it gives the application for the nano-edge placement feature, in other words, it's target is to increase the PWM signal resolution. It gives the example code and PWM waveform for the nano-edge placement feature.
View full article
  MCU Bootloader2.0.0 enables quick and easy programming of Kinetis MCUs through the entire product life cycle, including application development, final product manufacturing, and beyond. It supports many kinds of peripherals, include UART, I2C, SPI, USB, CAN and so on. Among these peripherals, UART is most common used. In reference manual, it only says that feature can be turned on or off by using #define statement in bootloader_config.h. In fact, you can use UART0 by default. But if you want to use other UART port, change TERM_PORT_NUM to other value is useless. If you traced this value, you’ll find it is not used at all, nor the TERMINAL_BAUD. Here we use FRDM-KV31F512 as the example. We want to download image by UART2. First, we should modify peripherals_pinmux.h. #define BL_ENABLE_PINMUX_UART2 (BL_CONFIG_SCUART)     //line 38   //! UART pinmux configurations #define UART2_RX_PORT_BASE PORTE #define UART2_RX_GPIO_BASE PTE #define UART2_RX_GPIO_PIN_NUM 17               // PIN 16 in the PTB group #define UART2_RX_FUNC_ALT_MODE kPORT_MuxAlt3   // ALT mode for UART0 RX #define UART2_RX_GPIO_ALT_MODE kPORT_MuxAsGpio // ALT mode for GPIO functionality #define UART2_RX_GPIO_IRQn PORTE_IRQn #define UART2_RX_GPIO_IRQHandler PORTE_IRQHandler #define UART2_TX_PORT_BASE PORTE #define UART2_TX_GPIO_PIN_NUM 16             // PIN 17 in the PTB group #define UART2_TX_FUNC_ALT_MODE kPORT_MuxAlt3 // ALT mode for UART0 TX   The original define is UART0, here we change it to UART2. It is strongly recommended to do so. Otherwise you’ll find that UART can’t work at all. Another comment here is PTE16 and PTE17 is conflict with SPI. You must disable SPI or change SPI function to other pins.   Next we must modify peripherals_KV31F512.h. const peripheral_descriptor_t g_peripherals[] = { #if BL_CONFIG_SCUART    // UART0    {.typeMask = kPeripheralType_UART,      .instance = 2, // change this value from 0 to 2      .pinmuxConfig = uart_pinmux_config,      .controlInterface = &g_scuartControlInterface,      .byteInterface = &g_scuartByteInterface,      .packetInterface = &g_framingPacketInterface },   Although there is a baud rate definition TERMINAL_BAUD, but it is never used too. MCU bootloader2.0.0 use auto baud rate detection. When power on, bootloader will go to autobaud detection mode. KinetisFlashTool sends ‘0x ’ every second. Bootloader check this byte and calculate baud rate.   After getting this value, bootloader will change to normal communication mode. Baud rate will not change until reset. If blhost is used, subsequent blhost invocations must specify the same baud rate as was used for the initial invocation unless the bootloader is reset. If the baud rate is not specified using the -p COMx, <baudrate> option, the UART baud rate will be set to 57600. Since Kinetis MCU UART module don’t have auto frequency detect function, the bootloader detects frequcny by software. It uses GPIO interrupt and timer to measure frequency. But in bootloader, there is only code for UART0, there isn’t code for other UART port. We must add the code. In hardware_init_KV31F512.c, modify the function get_uart_clock()   uint32_t get_uart_clock(uint32_t instance) {    switch (instance)    {        case 0:        case 1:            // UART0 and UART1 always use the system clock            return SystemCoreClock;        case 2:            return get_bus_clock();        default:            return 0;    } }   KV31 has 4 UART, include three UART modules and one low-power UART. They have different clock source. UART0 and UART1 use System clock while UART2 and LPUART0 use Bus clock. Thus, we finished the work. UART2 can work as the download port now.
View full article
The AOI and Crossbar modules are inregrated in DSC, Kinetics KV and i.mxrt families, user can use them to generate complicated trigger signal for the on-chip peripherals. The DOC discusses the AOI function, crossbar fuction based on KV58. It gives the example, the example demos how to implement AND operation of two signals via crossbar switch A and B and AOI modules. The two logic signals are connected to the pads of KV58, and routed to AOI inputs via Crossbar switch B, the AOI sub-module0 implements the AND operation of the two signals, and output the AND output signal Event0  to pad of KV58 via crossbar switch A. Connect input pads and output pad of KV58 to oscilloscope, from the waveform of the three signals on scope, we can see that the AND logic  is implemented.
View full article
How to byte program SPI flash via QSPI QSPI module are used in many Kinetis MCU, like K8x, K27/28 and KL8x. QSPI expands the internal flash range and can run in a fast speed. Compared to DSPI, QSPI is very complex and often takes a lot of time to learn. In KSDK there are two QSPI demo which shows how to program SPI flash in DMA mode and polling mode. Both of them program the QSPI flash with a word type array. But can the QSPI module program SPI Flash in byte? Yes, this article shows how to do it. Device: FRDM_KL82Z Tool: MCUXpresso IDE Debug firmware: JLINK I build the test project base on KL82 SDK/driver_example/qspi/polling_transfer. To byte program SPI flash, a new LUT item must be added. uint32_t lut[FSL_FEATURE_QSPI_LUT_DEPTH] =    { /* Seq0 : Quad Read */          /* CMD:       0xEB - Quad Read, Single pad */          /* ADDR:       0x18 - 24bit address, Quad pads */          /* DUMMY:     0x06 - 6 clock cyles , Quad pads */          /* READ:       0x80 - Read 128 bytes, Quad pads */        …        …        [32] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x02, QSPI_ADDR, QSPI_PAD_1, 0x18),        [13] = QSPI_LUT_SEQ(QSPI_WRITE, QSPI_PAD_1, 0x1, 0, 0, 0),        …        /* Match MISRA rule */        [63] = 0}; This item tells system how to program a single byte. Then when we write the data to TxBuffer, we must write the byte 4 times. This is because a write transaction on the flash with data size of less than 32 bits will lead to the removal of four data entry from Txbuffer. The valid bit will be used and the rest of the bits will be discard. Then before we start programming, we must set the data size.      QSPI_SetIPCommandSize(EXAMPLE_QSPI,1);   After byte program, we can see the result from 0x68000000. Attachment is the demo project. You can find that 0x03 was written to 0x68000005 after running.
View full article
Hey there Kinetis lovers!  We in the Systems Engineering team for Kinetis Microcontrollers see all kinds of situations that customers get into, and none can be particularly troubling like how the reset pin is handled.  The purpose of this document is to provide a list of Frequency Asked Questions (FAQ) that we get here in the Kinetis Systems Engineering department.  This is intended to be a living list and as such, may in no way be complete.  However we hope that you will find the below questions and answers useful.   Q:  Do I need to connect the reset signal to be able to debug a Kinetis device?   This is a commonly asked question. Strictly speaking, you do not need to connect the device reset line of a Kinetis device to the debug connector to be able to debug. The debug port MDM-AP register allows the processor to be held in reset by means of setting the System Reset Request bit using just the SWD_CLK and SWD_DIO lines.   However, before deciding to omit the reset line from your debug connector you should give some careful thought to how this may impact the ability to program and debug the device in certain scenarios. Does the debugger/flash programmer or external debug pod require the reset pin? It may be that the specific tool you are using only supports resetting the device by means of the reset line and does not offer the ability to reset the device by means of the MDM-AP. Have you changed the default function of the debug signals? You may need to use the SWD_CLK and/or the SWD_DIO signals for some other function in your application. This is especially true in low pin count packages. Once the function is changed (by means of the PORTx_PCRy registers) you will no longer have access to the MDM-AP via those signals. If you do not have access to the reset signal then you have no way of preventing the core from executing the code that will disable the SWD function of the pins. So you will not be able to re-program the device. In order to prevent this type of situation you need to either: Setup your code to change the function of the SWD pins several seconds after reset is released so that the debugger can halt the core before this happens. Put some kind of “backdoor” mechanism in your code that does not re-program the SWD function, or re-enables the SWD function, on these pins. For example, a specific character sequence sent via a UART or SPI interface.   Some Kinetis devices allow the reset function of the reset pin to be disabled. In this case you can only use the SWD signals as a means of resetting the device via the MDM-AP. If you change the SWD pin function in addition to disabling the reset pin then you must provide a backdoor means of re-enabling the SWD function if you want to be able to reprogram the device.
View full article
The documentation is only for eFlexPWM module of KV58, it describes the feature of nano-edge PWM, the mechanism of nano-edge PWM, and give the waveform which can describe the feature of nano-edge PWM. The attachment includes the brief introduction of nano edge PWM, the waveform of nano edge PWM, and the code which runs on TWR-KV58 and KDS3.0. Original Attachment has been moved to: eFlexPWMNanoEdgeKV58_2.rar
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
1.jicheng0622-AET-电子技术应用 2.wuyage-AET-电子技术应用 3.fanxi123-AET-电子技术应用
View full article
Revise History: Version 23: NXP kinetis bootloader GUI upgrade from v1.0 to v1.1: added 04 extended linear address record  and 02 sector address record processing for hex format. This article describes how to do in-system reprogramming of Kinetis devices using standard communication media such as SCI. Most of the codes are written in C so that make it easy to migrate to other MCUs. The solution has been already adopted by customers. The pdf document is based on FRDM-KL26 demo board and Codewarrior 10.6.  The bootloader and user application source codes are provided. GUI and video show are also provided. Now the bootloader source code is ported to KDS3.0, Keil5.15 and IAR7.40 which are also enclosed in the SW package. Customer can make their own bootloader applications based on them. The application can be used to upgrade single target board and multi boards connected through networks such as RS485. The bootloader application checks the availability of the nodes between the input address range, and upgrades firmware nodes one by one automatically. ​ Key features of the bootloader: Able to update (or just verify) either single or multiple devices in a network. Application code and bootloader code are in separated projects, convenient for mass production and firmware upgrading. Bootloader code size is small, only around 2K, which reduces the requirement of on chip memory resources. Source code available, easy for reading and migrating. GUI supports S19,HEX and BIN format burning images. For more information, please see attached document and code. The attached demo code is for KL26 which is Cortex - M0+ core. For Cortex-M4 core demo, refer this url: https://community.freescale.com/docs/DOC-328365 User can also download the document and source code from Github: https://github.com/jenniezhjun/Kinetis-Bootloader.git Thanks for the great support from Chaohui Guo and his team. NOTE: The bootloader and GUI code are all open source, users can revise them based on your own requirement. Enjoy Bootloader programming 🙂
View full article
This document explains a potential issue where interrupts appear to be disabled after enterring debug mode. This is as a result of the NMI being active when debug is enabled.
View full article
Kinetis KV10 chip is the entry point of the V Series product, which are designed for a wide range of BLDC, PMSM and ACIM motor control and digital power conversion applications. KV10 is using ARM Cortex-M0+ core, the core frequency could up to 75MHz. And KV10 provides various feature powerful modules, such as ADC modules (2x 16-bit ADCs with two capture and hold circuits and up to 1.2 MS/s samples rate in 12-bit mode — simultaneous measurement of current and voltage phase, reduced jitter on input values improving system accuracy 12-bit mode) and DMA modules (4-channel DMA — reduced CPU loading for improved application performance). The demo is using PDB hardware trigger two ADC modules conversion (12-bit single-ended mode) at the same time; the two ADC modules will trigger each related DMA channels to transfer ADC result to ADC buffer located at SRAM (start from 0x2000_0000) when finish each conversion. The ADC DMA channel 0 will link to trigger DMA channel 2 to transfer ADC result from ADC result buffer to SPI FIFO. When DMA channel 2 transfer done, in related interrupt service routine will software trigger PDB to start the next round of ADC conversion. Below is the processing chart: For the customer requires to transfer 9 ADC conversion results out (5 of ADC0 and 4 of ADC1) , the ADC buffer need interleaved storage result from two ADC modules. Below diagram shows the detailed info: Below is the test result and test environment. It will take almost 15.4us to get and transfer all 9 12-bit ADC conversion results. The demo code is attached. The project is based on TWR-KV10Z32 Sample Code Package could be downloaded from here. Wish it helps.
View full article
Hey All, Check out the unboxing video for UAV Drone designed using Kinetis V series MCUs to be showcased in Freescale Technology Forum 2015 at booth 249. The Kinetis V series 32-bit MCUs are based on ARM Cortex M cores and specially designed to enable motor control and power conversion applications. Please visit Kinetis V Series Webpage for more information. This drone is powered by Kinetis KV5x MCU (First Kinetis MCU with the latest ARM Cortex M7 Core). The Kinetis KV5x is used in Electronic Speed Control (ESC) unit and a single Kinetis KV5x MCU chip is used to control 4 Brushless DC motors which typically is controlled by four 8 bit MCUs. Along with controlling four motors, the KV5x MCU has enough performance and peripheral headroom so that it can be used as a flight controller and communication interface with connectivity features such as CAN and Ethernet. Kinetis KV5x is ideal solution for industrial IOT with the applications such high performance motor control and power conversion and real time control. Please visit Kinetis KV5x Series Webpage for more information. There is another drone in the Analog section at Freescale Technology Forum based on Kinetis KV4x MCU (based on ARM Cortex M4 core) and Freescale GD3000 3-Phase Brushless DC Gate driver. The Kinetis KV4x MCU is used to control 4 Brushless DC motors and is the cost optimized version of Kinetis KV5x MCUs. Please check out the Kinetis based drone demo as well as other cool demos at Freescale Technology Forum . PS: I apologize for the quality of the video. Working on the better video and editing skills.  Thanks, Mohit Kedia
View full article
Reference Solution being developed with Kinetis V (also can be done with a Kinetis K device) of a Class-D audio amplifier. 16-bit ADC sampling the audio input FlexTimer doing the PWM's for the Class-D amplifier DC/DC switched power supply with input of 12V and output of 130V to 180V (generates the power you need for making some good noise - 1kW) being controlled by the Kinetis MCU also. Capabiltiy of Audio processing/filtering using the Cortex-M4 DSP capabilities. Solution originally designed for cost-effective Automotive aftermarket sound systems. But can be adapted for implementing other audio amplifier applications also in the consumer space! Can you thing of cool applications/markets that this solution can be also quickly adapted? Soon, plan to make the reference solution design files available in the community. Stay tunned. Cheers! PK
View full article
For Remote Control means, that is needed two computers - Server Computer and User Computer, which will be in connection. There are two types of connection, which can be used - HTTP or DCOM. There are two different ways how to set up the remote control in Windows. I made the tutorial, which describes both types of Remote Control. Ok - so, let´s start! HTTP Settings On the Server Computer side: 1. Plug the board to the Server Computer 2. Go to Remote Communication Server 3. Set HTTP connection and choose the right COM Port according the plugged board If the plugged board is on e.g. COM23, it is possible to edit number of Port in Device Manager On the User PC side: 1. Open FreeMASTER,  go to Project -> Options 2. Choose Plug-in Module: FreeMASTER CommPlugin for Remote Server (HTTP) and type the IP address of the server, do not forget join to IP address :8080 3. And start communication by STOP button to successful connection DCOM Settings On the Server Computer side: 1. Plug board to the Server Computer 2. Launch DCOM in FreeMASTER Remote Server Choose COM according plugged board or edit COM according to step 2 - Server Computer in HTTP Connection (up). 3. Setting permissions for the user, User PC. Right click on Computer -> Manage. In Computer Management click to Distributed COM Users. In Distributed COM Users Properties add the user, User Computer. After that, set the permissions in Component Services. In cmd type dcomcnfg.exe In Component Services go to Computers -> My Computer -> DCOM Config -> MCB FreeMASTER Remote Server Application Right click on MCB FreeMASTER Remote Server Application and go to Properties. In Security Tab is possible to add the permissions. There are 3 types of permissions. First permission - Launch and Activation Permissions. There are 4 permission options. Local Launch and Remote Launch means, that user, User Computer can launch e.g. FM Remote Server Application. But for success communication is needed allowing Local Activation and Remote Activation. Second permission - Access Permissions. Click to Edit and Allow Local Access and Remote Access for the user. Do not forget that if there is a change of permissions, specifically allowing, it is necessary for User to log out and log in. On the User Computer side: 1. Open Freemaster, go to Project -> Options 2. Choose Plug-in Module: FreeMASTER CommPlugin for Remote Server (DCOM) and for filling Connect string is possible to use Configure. Definitely, type the IP address of the server and ;Port Name. 3. And start communication by STOP button in FreeMASTER to successful connection And now.. you can do anything 🙂
View full article
Introduction Even with the prevalence of universal asynchronous receiver/transmitter (UART) peripherals on microcontrollers (MCUs), bit banged UART algorithms are still used.  The reasons for this vary from application to application.  Sometimes it is simply because more UARTs are needed than the selected device provides.  Maybe application or layout restrictions require certain pins to be used for the UART functions but the device does not route UART pins to the required package pins.  Maybe the application requires a non-standard or proprietary UART scheme. Whatever the reason, there are applications where a bit banged UART is used and is typically a pure software implementation (a timer is used and the MCU core controls a GPIO pin directly).  A better alternative may be to use Flextimer (FTM) or Timer/PWM Module (TPM) to take advantage of the features of these peripherals and possibly offload the CPU.  This document will explain and provide a sample application of how to emulate a UART using the FTM or TPM peripheral.  A Kinetis SDK example (for the TWR-K22F120M and FRDM-K22F platforms) and a baremetal legacy code example (for the FRDM-KL26Z) are provided here. UART protocol Before creating an application to emulate a UART, the UART protocol and encoding must be understood. The UART protocol is an asynchronous protocol that typically includes a start bit, payload (of 7-10 data bits) , and a stop bit but does allow for many variations on the number of stop bits and what/how to transfer the data.  For this document and application example, the focus will be UART transmission that follows 1 start bit, 8 data bits, 1 stop bit, no parity, and no flow control.  The data will be transmitted least significant bit (LSB) first.  The following image is a block diagram of this transmission. However, this doesn't specify what the transmission looks like electrically. The figure below shows a screenshot of an oscilloscope capture of a UART transmission.  The data transmitted is 0x55 or a "U" in the ASCII representation. Notice that the transmission line is initially a logic high, and then transitions low to signal the start of the transmission.  The transmission line must stay low for one bit width for the receiver to detect it.  Then there are 8 data bits, followed by 1 stop bit.  In the case shown above, the data bits are 0x55 or 0b0101_0101.  Remember that the transmissions are sent LSB first, so the screenshot shows 1-0-1-0-1-0-1-0.  The last transition high marks the beginning of the stop bit and the line remains in that state until the start of the next transmission.  The receiver, being asynchronous, does not require any type of identifying transition to mark the end of the stop bit. FTM/TPM configuration The first question many may ask when beginning a project like this is "How do I configure the FTM/TPM when emulating a UART".  The answer to this depends on the aspect of this problem you are trying to solve.  Transmitting and receiving characters require two different configurations.  Transmission requires a configuration that manipulates the output pin at specific points in time.  Receiving characters requires a configuration that samples the receive pin and measures the time between pin transitions.  The FTM and TPM have the modes listed in the following table: The FTM and TPM have four different modes that manipulate an output:  Output compare (no pulse), Output compare (with pulse), Edge-aligned PWM, and Center-aligned PWM.  Neither PWM mode is ideal for the requirements of the application.  This is because the PWM modes are designed to produce a continuous waveform and are always going to return to the initialized state once during the cycle of the waveform.  However, the UART protocol may have continuous 1's or 0's in the data without pin transitions between them. The output compare mode (high-true or low-true pulse modes) is designed to only manipulate the pin once, and only produces pulses that are one FTM/TPM clock cycle in duration.  So this is obviously not desirable for the application.  The output compare mode (Set/Clear/Toggle on match) is promising.  This mode manipulates the output pin every cycle.  There are three different options:  clear output on match, set output on match, and toggle output on match.  Neither "clear output on match" nor "set output on match" are ideal as either would require configuration changes during the transmission of a character.  The "toggle output on match", however, can be used and is the selected configuration mode for this sample application. To receive characters, there is only one mode that is intuitive:  "the input capture mode".  This mode records the timer count value on an edge transition of the selected input pin.  Similar to the output compare mode chosen for the transmit functionality, the input capture mode has three sub-modes:  capture on rising edge, capture of falling edge, and capture on either edge.  It is clear from the descriptions that capture on either edge should be selected. Transmit encoding The selection of the FTM/TPM mode is moderately intuitive, but using this mode to emulate a UART transmission is not.  There are two issues that make this a little tricky. 1) The output pin is initialized low. However, the UART protocol needs the pin to begin in a logical high state. 2) The pin transitions on every cycle provided the channel value is less than the value of the MOD register. Due to continuous strings of 1's or 0's, it is necessary to have periods where the pin does not transition. Both of these points have workarounds. Output pin initialization For the first issue, the channel interrupt is first enabled and the channel value register is loaded with a value much less than the value in the MOD register.  Then in the channel interrupt service routine, the pin is sampled to ensure that it is in the logic high state and the channel interrupt is disabled (and will not be re-enabled throughout the life of the application).  The code for this interrupt service routine is as follows. Output pin control For the second issue, a method of not transitioning the pin value while allowing the timer to continue counting normally is necessary.  The Output Compare mode uses the channel value register to determine when the pin transition occurs.  If a value greater than MOD is written to the channel value register, the channel value will never match the count register and thus, a pin transition will never occur.  So, when a series of continuous 1's or 0's need to be transmitted, a value greater than the value in the MOD register can be written to the channel value register to keep the output pin in its current state. However, when a value greater than MOD is written to the channel value register, no channel match will occur (which means channel interrupts will not occur).  So the timer overflow interrupt must be used to continue writing values.  This requires the updates to be output pin to be planned ahead of time and makes the transmission algorithm a little tricky.  The following diagram displays when which values should be written to the channel value register at which points in time to generate the appropriate pulses. Writing a function to translate a number into the appropriate series of MOD/2 and MOD+1 values can be a little tricky. To do this, we must first notice that MOD/2 needs to be written when changes on the transmission pin are need and MOD+1 needs to be written when pin transmissions are not desired.   So, what logical function can we use to determine when a change has happened?  XOR is the correct answer.  So what two values need to be XOR'd together?  One value is obviously the value that we want to send.  But what is the second value?  It turns out that the second value is a shifted version of the value that we want to send.  Specifically, the second value is the desired value to send shifted to the left by one.  (You can think of it as sort of a "future" value of the desired value).  The following pictures show how to determine the queue to use for the transmission. Receive decoding The receive functionality has an advantage over the transmit functions in that it is possible to use DMA for the reception of characters.  This is because the receive function takes advantage of the input capture functionality of the FTM / TPM and therefore can use the channel match interrupt.  The example application provided with this document implements a DMA method and a non-DMA method for reception. First, the non-DMA method will be discussed. Before discussing the specifics of gathering the input pulse widths, some details of the receive pin need to be discussed. Detecting the start bit The receive pin needs to be able to determine when the start of the packet transmission begins.  To do this, the receive pin is configured as an FTM / TPM pin. At the same time, the GPIO interrupt functionality is configured on the same pin for a falling edge interrupt.  The GPIO interrupt capabilities are enabled in any digital mode, so the GPIO interrupt will still be able to be routed to the Nested Vector Interrupt Controller (NVIC).  The pin interrupt is used to start the FTM / TPM clock when a new character reception begins. In the GPIO interrupt for this pin, the FTM / TPM counter register is reset and the clock to the FTM / TPM is turned on.  The code for the GPIO interrupt service routine is shown below.  Receiving characters without DMA Now, when receiving characters and not using DMA, the first thing to understand is that the Interrupt Service Routine (ISR) will be used and it will mainly be used to record the captured count values.  The interrupt service routine also tracks the current receive character length and resets the counter register.  This is so that the values in the receive queue reflect the time since the last pin transition.  The interrupt function for the non-DMA application is shown below. Notice that the first two actions in the ISR are resetting the count register, and clearing the channel event interrupt flag.  Then the channel value is stored in the receive pulse width array (this is simply an array that holds the receive pulse widths of the current character being received).  Next, recvQueueLength , the variable which holds the current length of the character being received, is updated to reflect the latest character length.  The next step is to determine if the full character has been received.  This is determined by comparing recvQueueLength to the RECV_QUEUE_THRESH , which is the threshold as determined by multiplying the number of expected bits by the expected bit width plus another bit width (for the start bit).  If the recvQueueLength is greater than the RECV_QUEUE_THRESH , then a semaphore is set, recvdChar , to indicate that a full character has been received.  The FTM / TPM clock is turned off, and the pin interrupt functionality of the receive pin is enabled.  The final step in the interrupt routine is to increment the receive queue index, recvQueueIndex .  This variable points to the current entry in the receive queue array. Using DMA to receive characters When using DMA, the receive FTM / TPM interrupt is much different. The interrupt routine simply needs to clear the channel interrupt flag, stop the FTM / TPM timer, disable the DMA channel, and set the received character semaphore.  The character is then decoded outside of the interrupt routine.  The interrupt function when using DMA is shown below: Decoding the received pulse widths Once the array of pulse widths has been populated, the received character needs to be translated into a single number.  This varies slightly when using DMA and when not using DMA. However, the basic principle is the same.  The number of bits in a single entry is determined by dividing by the expected bit width and this is translated into a temporary array that contains 1's and 0's, and then that is used to shift in the appropriate number of 1's and 0's into the returned char variable.  A temporary array is needed because the values are shifted into the UART LSB first, so the bit must be physically flipped from the first entry to the last.  There is no logical operation that will do this automatically. The algorithm to perform this translation is shown below.  In this algorithm, note that recvPulseWidth is the array that contains the raw count value of the pulse width.  The array tempRxChar holds the decoded character in reverse order and rxChar is a char variable that holds the received character. Conclusion This document provides an overview of the UART protocol and describes a method for creating a software UART using the timing features of the FTM or TPM peripheral.  This method allows for accurate timing and while not relying entirely on the CPU and the latency associated with the interrupt and the GPIO pins.  The receive function is open to further optimization by using DMA, which can provide further unloading of the CPU.
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
Introduction What is a gated timer and why would I need one? A gated timer is a timer whose clock is enabled (or "gated") by some external signal.  This allows for a low code overhead method of synchronizing a timer with an event and/or measuring an event. This functionality is not commonly included on Freescale microcontroller devices (this functionality is only included on d evices that are equipped with the upgraded TPM v2 peripheral; currently K66, K65, KL13, KL23, KL33, KL43, KL03) but can be useful in some situations.  Some applications which may find a gated timer useful include asynchronous digital sampling, pulse width duty cycle measurement, and battery charging. How do I implement a gated timer with my Kinetis FTM or TPM peripheral? To implement a true gated timer with a Kinetis device (that does not have the TPM v2 peripheral), additional hardware will be required to implement the enable/disable functionality of a gated timer.  This note will focus on two different ways (low-true and high-true) to implement a gated timer.  The method used will depend on the requirements of your application. Implementing a gated timer for Kinetis devices without the TPM v2 peripheral requires the use of a comparator and a resistive network to implement a gated functionality (NOTE:  Level shifters could be used to replace the resistive network described; however, a resistive network is likely more cost effective, and thus, is presented in this discussion).  Figure 1 below is the block diagram of how to implement a gated timer functionality.  The theory behind this configuration will be explained in later sections. Theory of Operation Comparator and resistive network implementation The comparator is the key piece to implementing this functionality. For those with little experience with comparators (or need a refresher), a comparator is represented by the following figure.  Notice that there are three terminals that will be of relevance in this application: a non-inverting input (labeled with a '+' sign), an inverting input (labeled with a '-' sign), and an output. A comparator does just what the name suggests: it compares two signals and adjusts the output based on the result of the comparison.  This is represented mathematically in the figure below. Considering the above figure, output of the comparator will be a  logic high when the non-inverting input is at a higher electric potential than the inverting input.  The output will be a logic low if the non-inverting input is at a lower electric potential than the inverting input.  The output will be unpredictable if the inputs are exactly the same (oscillations may even occur since comparators are designed to drive the output to a solid high or solid low).  This mechanism allows the clock enable functionality that is required to implement a gated timer function provided that either the non-inverting or inverting input is a clock waveform and the opposite input is a stable logic high or low (depending on the desired configuration) and neither input is ever exactly equal.  Comparator Configurations There are two basic signal configurations that an application can use to enable the clock output out of the comparator: low-true signals and high-true signals.  These two signals and some details on their implementation are explained in the following two sections.  Low-true enable A low-true enable is an enable signal that will have zero electric potential (relative to the microcontroller) or a "grounded" signal in the "active" state.  This configuration is a common implementation when using a push button or momentary switch to provide the enable signal.  When using this type of signal, you will want to connect the enable signal to the non-inverting input of the comparator, and connect the clock signal to the inverting input. The high level of the enable signal should be guaranteed to always be the highest voltage of the input clock plus the maximum input offset of the comparator. To find the maximum input offset of the comparator, consult the device specific datasheet.  See the figure below to see a graphical representation of areas where the signal will be on and off. The external hardware used should ensure that the low level of the enable signal never dips below the lowest voltage of the input clock plus the maximum input offset of the comparator. The following figure displays one possible hardware configuration that is relatively inexpensive and can satisfy these requirements. High-true enable A high-true enable is an enable signal that will have an electric potential equal to VDD of the microcontroller in the "active" state.  This configuration is commonly implemented when the enable signal is provided by an active source or another microcontroller.  When interfacing with this type of signal, you will want to connect the enable signal to the inverting input of the comparator, and connect the clock signal to the non-inverting input.  When the comparator is in the inactive state, it should be at or below the lowest voltage of the clock signal minus the maximum input offset of the comparator.  Refer to the following figure for a diagram of the "on" and "off" regions of the high true configurations. The external hardware will need to guarantee that the when the enable signal is in the active state, it does not rise above the highest voltage of the clock signal minus the maximum input offset of the comparator. The following figure displays one possible hardware configuration that is relatively inexpensive and can satisfy these requirements. Clocking Options Clocking waveform requirements will vary from application to application.  Specifying all of the possibilities is nearly impossible.  The point of this section is to inform what options are available from the Kinetis family and provide some insight as to when it might be relevant to investigate each option. The Kinetis family provides a clock output pin for most devices to allow an internal clock to be routed to a pin.  The uses for this option can vary.  In this particular scenario, it will be used to provide the source clock for the comparator clock input. Here are the most common clock output pin options across the Kinetis K series devices.  (NOTE:  If the application requires a clock frequency that the CLKOUT signal cannot provide, a separate FTM or TPM instance or another timer module can be used to generate the required clock.) In the Kinetis L series devices, the following options will be available. The clock option selected should be the slowest allowable clock for the application being designed.  This will minimize the power consumption of the application.  For applications that require high resolution, the Bus, Flash, or Flexbus clock should be selected (note that the Flexbus clock can provide an independently adjustable clock, if it is not being used in the application, as it is always running).  However, if the target application needs to be more power efficient, the LPO or MCGIRCLK should be used.  The LPO for the Kinetis devices is a fixed 1 kHz frequency and will, therefore, only be useful in applications that require millisecond resolutions.
View full article