Kinetisマイクロコントローラ・ナレッジ・ベース

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

Kinetis Microcontrollers Knowledge Base

ディスカッション

ソート順:
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
記事全体を表示
Bootloader是一种面向用户应用程序的引导代码,可以在没有烧写器的情况下烧录用户程序,也可以用于在线更新程序。飞思卡尔提供了三种实现bootloader的方式,分别为: 1.预烧写在ROM中的bootloader     这种方式是MCU中内置了专用的ROM来存放bootloader,目前支持ROM型bootloader的Kinetis系列MCU包括KL03,KL17,KL27和KL43等。其中KL03和KL17的ROM bootloader包含SPI/UART/IIC三种接收方式,KL27和KL43还增加了USB的方式。 2.预烧写在FLASH中一次性bootloader     这种类型的bootloader在芯片出厂前预写在FLASH中,因此可以像ROM型bootloader一样直接使用。但与ROM型不同的是,上电后bootloader会从FLASH搬移到RAM 中运行,再将FLASH整片擦除并烧写用户程序,因此这种bootloader是一次性的。其优点是不需要片内ROM且方便量产烧写,缺点是无法支持以后的程序更新。目前支持预烧写在FLASH中一次性bootloader的Kinetis系列MCU包括K22、K24和KV3x等。 3.开放源码的bootloader     这种方式将FLASH空间分为两个部分,一部分用于存储bootloader代码;另一部分用于存储用户应用程序代码。这种方式的bootloader方便客户定制自己的代码。     目前飞思卡尔提供开放源代码的Kboot,支持UART/SPI/IIC/USB HID 几种接口方式,其网址链接为:     www.freescale.com/kboot     除了Kboot,还有以下独立版本的bootloader,包括:     1)AN2295(开发人员的串行引导加载程序)         文档下载地址为:http://cache.freescale.com/zh-Hans/files/microcontrollers/doc/app_note/AN2295.pdf         代码下载地址为:http://cache.freescale.com/files/microcontrollers/doc/app_note/AN2295SW.zip        另外FAE Yang Liang 对其进行了移植,目前已经支持FRDM-KE02,KE06,KL25,KL26,KL43,KL46, TWR-K60, KV4x, KV10.下载地址为:Kinetis/AN2295_Bootloader · GitHub     2)AN4767 (Kinetis E 系列上的UART Boot Loader 设计)         文档下载地址为:http://cache.freescale.com/zh-Hans/files/32bit/doc/app_note/AN4767.pdf         基于AN2295,没有提供代码。     3)AN4775 (Kinetis E 系列上的IIC Boot Loader设计)         文档下载地址为:http://cache.freescale.com/zh-Hans/files/32bit/doc/app_note/AN4775.pdf         代码下载地址为:http://cache.freescale.com/files/32bit/doc/app_note/AN4775SW.zip     4)AN4368 (USB 大容量存储设备主机引导加载程序)          文档下载地址为:http://cache.freescale.com/zh-Hans/files/microcontrollers/doc/app_note/AN4368.pdf          代码下载地址为:GitHub - Wangwenxue/USB_MSD_Host_Bootloader_K60: This is usb msd Bootloader for K60 (For K60)                                        GitHub - Wangwenxue/USB_MSD_Host_Bootloader_K64: This USB MSD bootloader for K64 (For K64)     5)AN4379  (Freescale USB大容量存储设备引导加载程序)          文档下载地址为:http://cache.freescale.com/zh-Hans/files/microcontrollers/doc/app_note/AN4379.pdf          代码下载地址为:http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4379SW.zip     6)AN4764   (USB Human Interface Device Boot Loader for ColdFire Plus, Kinetis K, and Kinetis L MCUs)          文档下载地址为:http://cache.freescale.com/files/32bit/doc/app_note/AN4764.pdf          代码下载见附件     7)AN4370   (用于 MCU 的 USB DFU 引导加载程序)         文档下载地址为:http://cache.freescale.com/zh-Hans/files/microcontrollers/doc/app_note/AN4370.pdf         代码下载地址为:http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4370SW.zip       8)AN4367   (用于 MCU 的 以太网引导加载程序)         文档下载地址为:http://cache.freescale.com/zh-Hans/files/microcontrollers/doc/app_note/AN4367.pdf?fromsite=zh-Hans         代码下载地址为:http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4367SW.zip         最新的代码请到FNET官网下载:http://fnet.sourceforge.net/    9)Kinetis Bootloader to Update Multiple Devices in a Network - for Cortex-M0+         代码及文档下载地址为:https://community.freescale.com/docs/DOC-328168            
記事全体を表示
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
記事全体を表示
Introduction This document is being written to communicate the need for serialization of memory operations and events in an end application.  In addition, directions will be provided to properly serialize memory operations in the end application.  Memory operations and event serialization applies to all Kinetis devices but is only necessary in specific scenarios. These scenarios include memory writes and reads, clearing status flags, and changing mode control operations. Serialization of memory operations Serialization of memory operations or events is the action of guaranteeing that said memory operations or events are executed in a specific order.  This action is required when making a change to a peripheral module when that change must complete before continuing with program execution.  Users often make the mistake of assuming that since a peripheral register has been written to, the change is in effect immediately.  However, this is not always the case.  The Kinetis series devices implement a crossbar and peripheral bridge interface system that allows masters (the CPU, DMA, etc.) to interface with the peripherals.  The crossbar allows multiple masters to access the individual peripherals on the bus, and the peripheral bridge functions as a bus protocol translator between the crossbar switch and the slave peripheral bus.  Wait states can be inserted at either stage of the communication channel (crossbar or peripheral bridge).  When a master attempts to access a slave and another master is already accessing this slave or the slave is busy, wait states will be inserted.  If the access is a write, then the master's write is simply pushed to the peripheral bus and the master continues.  However, if the access is a read, the master must wait for a response from the slave.  The slave may insert wait states in this communication as it must finish any commands (or writes) it was previously given before responding.    Peripheral module changes that require serialization actions include clearing interrupt service flags, changing power modes (of the module or the SOC as a whole), or software triggering a hardware event.  If the events or memory operations are not serialized in these situations, the CPU could go on to execute code with undesired effects. When do I need to serialize my memory operations and events? Memory operations and events require serialization anytime the program needs to guarantee that a peripheral access happens before code execution continues.  Examples of these situations includes: Exiting an interrupt service routine (ISR) Changing a clock mode or power mode Configuring a function Configuring a hardware change Software triggering a hardware event How do I serialize my memory operations and events? Memory operations are serialized by performing the following operations: Write the desired peripheral register Read the peripheral register that was just written Continue with the subsequent operations By simply reading the register that was just written, the core is forced to wait for a response from the peripheral module that was written before code execution can continue.   In this manner, it is guaranteed that the peripheral module will have completed the desired operations. Example event serialization The following is an example of a function that services the LPTMR ISR flag and implements the event serialization discussed in this document.  void lptmr_isr(void) {   // Declare dummy variable to store the read of the LPTMR0_CSR register volatile int dummy_var; /****   STEP #1  ****/   // Clear the flag; enable interrupts; enable the timer   LPTMR0_CSR = ( LPTMR_CSR_TEN_MASK | LPTMR_CSR_TIE_MASK | LPTMR_CSR_TCF_MASK  );   /****  STEP #2  ****/    // Store CSR register in dummy_var to serialize the clearing of the TCF flag   dummy_var = LPTMR0_CSR; } Conclusion In conclusion, there are situations where code execution can continue before a peripheral change has taken effect. These situations include clearing interrupt service flags, changing power modes (of the module or the SOC as a whole), or software triggering a hardware event.  Sometimes these events can cause unexpected results or even cause your application to crash.  These situations call for the serialization of memory operations and events, which is simply the act of guaranteeing that events and code are executed in a specific order.  To serialize memory operations, simply follow these directions: Write the desired peripheral register Read the peripheral register that was just written Continue with the subsequent operations Following these steps, you will be guaranteed that peripheral configurations have taken effect before continuing with the application. 
記事全体を表示
[EEPROM emulation driver for KEA128 and KEA8] software used for Kinetis EA family product (without integrated EEPROM memory), which using the sector-erasable Flash memory be used to emulate the EEPROM through EEPROM emulation software.  The software could downloaded from here: This document will interpret EEPROM emulation driver demo for KEA128 product and shows how the EEPROM emulation driver works and related API function introduction. 1> EEPROM emulation driver feature The EEPROM emulation driver for SGF/FTM flash family implements the fix-length data record scheme. Several sectors shall be involved in emulation with a round robin scheduling scheme. The EEPROM functionalities to be emulated include initializing, de-initializing, reading, writing records. The EEPROM emulation driver is more complicated than general Flash program data application with following features: User configurable emulated EEPROM size. Larger life for the flash memory used for EEPROM emulation. Unique feature of Cache Table which makes data retrieval fast. Support fix length record scheme only. Support synchronous model which can be run from both RAM and FLASH. When running from FLASH, user needs to relocate flash launch command routine to RAM to avoid Read While Write error. If any operation fails during EEPROM emulation, the driver will try to repeat that operation until successfully for several times (which is defined by user). If that operation still fails, the driver will make the related sector to DEAD to eliminate it from round robin sequence and continue other tasks without stopping driver. Concurrency support via callback. Release in C source code format. Ready-to-use demos illustrating the usage of the driver with different compilers. 2> Demo interpretation The demo routine located at default installation path: ..\\KEA EEPROM Emulation Driver\KEA_SGF180\Demos\build\TRK_KEAZ128\iar\Normal_demo folder. For the demo runs in Flash memory, avoiding Read While Write error happened, Eed_FlashLauchnCommand and g_EECallBack must be relocated to or placed in RAM when the main routine start. Then it will disable the cache and initialize Flash clock(KEA128 ICS module default clock mode is FEI, the default system/core clock is 21MHz, the Flash clock divider value set to 20 to make Flash clock to be 1MHz).   After flash clock initialized, it will initialize EEPROM configuration start address. The status of each sector with five value, which means Blanked, Alternative, Active, Dead and Invalid. The EE_ALLOTED_SECTORS macro will calculate the total number of sectors, which includes Active sectors and Alternative sectors. #define EE_ALLOTED_SECTORS              (EE_ACTIVE_SECTORS + EE_READY_SECTORS) The EE_ACTIVE_SECTORS value is 1 and EE_READY_SECTORS value is 2, so the EE_ALLOTED_SECTORS value is 3. Then there with three allotted sector, and allocated at below address:      eepromConfig.startSecAddr[0] = 0x1A00;      eepromConfig.startSecAddr[1] = 0x1C00;      eepromConfig.startSecAddr[2] = 0x1E00; After initialize start address for EEPROM configuration, following to call Eed_DeinitEeprom() function to erase all sectors used for emulation. Then it will initialize EEPROM emulation, includes to remove dead sector from EEPROM system and determine maximum valid index in array of start sector address after that; also includes initialize all sectors by erasing the “possible-error-sector”; and initialize and update cache table if enabled. It call Eed_InitAllSectors() function to initialize all sectors and allocate the current active sector to base sector. The Eed_ShiftIdxToBase() function will be called to shift the current index to base index of 0. After that, the EEPROM configuration startSecAddr array will change to :      eepromConfig.startSecAddr[0] = 0x1E00;      eepromConfig.startSecAddr[1] = 0x1A00;      eepromConfig.startSecAddr[2] = 0x1C00; The active sector start address at 0x1E00. Then it will program erase cycle value to each sector start address, the erase cycle value will occupy 4 bytes with sector start address offset 0: Then make the base sector to be active and program the active indicator at sector start address offset 8. Here the base sector start address is 0x1E00, the active indicator will be programmed at 0x1E08 with active indicator value 0x55555555: Then it will call Eed_SearchBlankSpace () function to find blank space of EEPROM system, in this demo, the blank space start address at 0x1e0c. If enable the Flash cache, the cache will be cleared and updated during EEPROM emulation initialize phase. The demo will write eight group data to EEPROM system, each group with 16 bytes data, total data number is 128 bytes. The data located at Flash start address is 0x1e0c. After each group data programming, it will following with the data ID info and program the status. With all data was written, the all 128 bytes data was programed at 0x1e00 start EEPROM sector. When the write data exceed the active EEPROM sector, the swapping will occur. The swapped EEPROM sector will record previous data and current write data. If there exist sector erase action, it will also update the erase cycle value. The data is full and the new data written will make swap happens: After swap happens: At the end of demo, it will read EEPROM data back and make sure all valid record ID are written to EEPROM emulation.
記事全体を表示
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.
記事全体を表示
   Android Open Accessory support allows external USB hardware (an Android USB accessory) to interact with an Android-powered device in a special accessory mode. When an Android-powered powered device is in accessory mode, the connected accessory acts as the USB host (powers the bus and enumerates devices) and the Android-powered device acts in the USB accessory role. This ADK library is based on Freescale Kinetis KL26 MCU, It implements some functions to communicate with android phone.
記事全体を表示
The FRDM-KL25Z is an ultra-low-cost development platform enabled by Kinetis L Series KL1 and KL2 MCUs families built on ARM® Cortex™-M0+ processor. Features include easy access to MCU I/O, battery-ready, low-power operation, a standard-based form factor with expansion board options and a built-in debug interface for flash programming and run-control. The FRDM-KL25Z is supported by a range of Freescale and third-party development software. Features MKL25Z128VLK4 MCU – 48 MHz, 128 KB flash, 16 KB SRAM, USB OTG (FS), 80LQFP Capacitive touch “slider,” MMA8451Q accelerometer, tri-color LED Easy access to MCU I/O Sophisticated OpenSDA debug interface Mass storage device flash programming interface (default) – no tool installation required to evaluate demo apps P&E Multilink interface provides run-control debugging and compatibility with IDE tools Open-source data logging application provides an example for customer, partner and enthusiast development on the OpenSDA circuit Take a look at these application notes: USB DFU boot loader for MCUs Developer’s Serial Bootloader. Low Cost Universal Motor Drive Using Kinetis L family . Writing your First MQXLite Application Learn more...
記事全体を表示
最近,有客户反映在IAR6.6 环境中,即便在程序中配置了Kinetis的加密字段“0x40C -0x40F”,但在实际程序运行中发现这些加密位并没有被真正的写进去。现根据Colleagues的分析,结合个人的理解总结如下,描述不清楚之处希望能提出宝贵意见。 原因:新版本的IAR 6.6 为了防止用户在使用Kinetis过程中误操作导致芯片被锁死,默认将加密位Disable了,在烧录Flash的时候设了最后一道闸门,将0x40C -0x40F的值统一成0xFFFFFFFE (解密模式)。 如果要完成加密, 可以修改其Flash Loader配置。 证据:在C:\Program Files\IAR Systems\Embedded Workbench 6.5_2\arm\config\flashloader\Freescale文件夹中,查看FlashK60Dxxx128K.board文件可以看到如下描述,其中<args_doc>与</args_doc>可以理解为一些注释,需要按解决方法的步骤设置。 <args_doc>.....--enable_config_write - allow programming of 0x40C - 0x40F with user supplied data, in other case flashloader after erase of block 0 will write 0xFFFFFFFE (unsecure state).</args_doc> 解决方法: 1) 打开IAR的Options配置框,选择Debuger的Download 标签,勾选如下图所示的选项,可以看到此项目中对应的.board文件; 2) 点击edit按钮, 显示如下对话框,两处分别对应着包含不同Flash Memory的器件设备; 3) 对于不包含FlexNVM的器件,选择0x0-0xfffffff对应的条目,然后选择Edit; 4) 在下面的对话框中的extra edit 项目中填写 “--enable_config_write” , 它意味着打开了在烧录Flash的时候设置的最后一道闸门,使能了用户对加密字段“0x40C -0x40F”的配置。关于此参数选项含义,可以查看下面框中parameters description的描述。 5) 选择OK , 回到上级对话框,如下图可以看到“--enable_config_write”作为一个Extra Parameters显示出来; 6)再次选择OK,回到上层对话框。 此处不用担心OK后修改的配置会替换Flash Loader中的默认配置,因为系统会自动保存刚才的修改到一个新的board文件,并存储到当前工程的文件目录中; 7) 选择“save ”,保存; 8) 选择"OK”,然后开始下载。 9) 如果以后需要加密的时候, 可以使用新的board文件, 不需要加密的时候,选择使用IAR下面的board文件。      至此,完成整个配置过程。 关于在J_flash中选择使用加密: 1)在Jflash中选择project settings; 2)在Project settings栏选择CPU标签,勾选Device选项,并点击Freescale MKL25Z128xxx4后面的方框; 3)在如下窗口Manufacturer中选择Freescale,找到对应的Device,选择带有"allow security"的选项,就可以支持加密了。否则即便在程序中Kinetis的加密字节设置了加密,代码也不会实     际的运行。
記事全体を表示
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.
記事全体を表示
This is an update to the KE0x Driver Library package with the example projects ported to Kinetis Design Studio (KDS).  These examples support the following boards: FRDM-KE02 FRDM-KE04 FRDM-KE06 The examples were tested with KDS v3.0.0
記事全体を表示
最近搞了一个基于TWR-K20D50M的的USB MSD device bootloader, 可以打开文件夹CW中的K20D5下的.project来查看。 在原始的MSD的基础上移植了FAT过来。 其他IAR和Kinetis的其他chip没有测试,如果需要使用,一个是新增相关头文件,二是在bootloader.h中修改相应的MCU_K20D50M定义下的flash及ram配置
記事全体を表示
Here you can find the code and project files for the GPIO example, in this example the 3 colors of the RGB led are turned on sequentially when the SW2 push button is pressed, the led pin definition is shared throughout all the freedom platforms. The wait function can be defined in seconds, miliseconds or microseconds. Code: #include "mbed.h" //Delay declared in seconds /*GPIO declaration*/ DigitalOut Red(LED1);         DigitalOut Green(LED2); DigitalOut Blue(LED3); DigitalIn sw2(SW2); int main() {     /*Leds OFF*/     Red=1;     Green=1;     Blue=1;         while(1)     {         if(sw2==0)         {             Red = 0;             wait(.2);             Red = 1;             wait(1);                                Green=0;             wait(.2);             Green=1;             wait(1);                         Blue=0;             wait(.2);             Blue=1;             wait(1);         }     } }
記事全体を表示
最近有客户问到如何移植PE生成的TSI代码到IAR中,按照常规的方法在把头文件和库文件意义一一包含进来,非常繁琐,于是研究了一下相关的操作。在早期的IAR版本中,需要用户自己手动添加芯片名称,链接文件和包含的路径信息,特别是在PE增加或者删除组件后,需要用户去增减相应的文件,更增加了难度。而在最新版本的 IAR 6.7中集成了对PE工程的链接机制,它可以方便的读取PE工程的XML文件,从而实现移植PE生成的代码到 IAR Embedded Workbench中,相对于早期的IAR版本,主要完成以下几个工作: 自动检测使用的芯片类型; 自动添加PE的LCF连接配置文件; 自动更新包含的头文件路径; PE增加或者删除Component组件后,IAR工程会自动Add 或Delete 相应的组件代码; 尽管IAR完成了一些繁琐的工作,但网上没有太多的资源可以参考,对于首次使用的用户来说还是需要一些探索,为节省大家的时间,下面以一个具体的示例Step By Step的介绍如何在IAR中集成PE的工程。 1. 打开Processor Expert software 新建一个PE的工程并保存生成代码,这个过程比较简单,此处不再赘述,重点讲述一下在IAR中的使用步骤; 2. 在IAR Workbench中"Creat New Project"新建一个空的工程。 3. 保存新建的工程文件到PE工程的文件夹中,需要注意的是此处也可以选择其他路径,但为简便和易维护性上还是建议直接存放到PE工程中。 4. 打开Tools->Options->Project选项,勾选“Enable project connects”,这个选项的目的在于使能 IAR 能够读取Freescale Processor Expert和Infineon DAVE等第三方工具生成.XML文件。 5. 添加PE工程的XML文件,选择Project->Add Project Connection,会弹出链接选择对话框,选择使用Freescale Processor Expert,默认是IAR Project Connection; 6. 点击OK后,选择建立PE工程时生成的工程描述符文件Projectinfo.xml; 7. 完成上面步骤后,在IAR中自动完成以下三方面工作:自动加载PE生成的文件到IAR中,自动安装LCF链接配置文件,自动包含头文件路径。这几个步骤在之前版本的IAR中需要自己手动添加,并且当在PE中重新生成Code时需要重新添加对应的文件; 8. 完成上面步骤之后,需要根据实际情况配置采用的下载/调试器,Project->Options->Debugger->Setup 选择下载Driver,实验中使用的是KL25的FRDM板,所以在PE Macro中选择OpenSDA,点击OK,完成设置; 9. 编译工程,下载Debug; 总结下来,主要完成两个工作:(1)配置使能 Project connection,并导入PE生成的XML文件; (2)配置调试的下载器仿真器;
記事全体を表示
Hi Community members! Here you can find the source code of the MSD Host Bootloader implemented on the AN4368 document using the TWR-K70F120M and CodeWarrior 10.6 and a document that describes the migration process of the original source code for the TWR-K60N512 to a TWR-K70F120M and the steps to use the application. Attached you will find a image.s19 file created to be used with the bootloader application as an example. :smileyinfo: This document and code are intended to demonstrate the use of the AN4368 source code on a 120 MHz device and CodeWarrior 10.6 but is not replacing the work done on the application note. I hope this can be helpful for you! Best Regards, Adrian :smileyplus: If it was useful for you do not forget to click on the Like button. It would be nice!
記事全体を表示
I have definitely experienced some of the growing pains of using the Kinetis tools as they have underdone some changes.  I started tinkering with KDS last year when KSDK and MQX were separate packages.  I didn't mess around with it much, other than to prove that I could toggle some GPIO.  I then got more serious with KDS 2.0 and KSDK 1.1 when MQX was integrated into the installer.  I started with simple projects, and eventually got a pretty good demo put together that incorporated ethernet (using lwIP), RS485, Modbus TCP/RTU, motion control, and barcode reading.  Unfortunately, at that time there were some small issues with the KSDK 1.1 which prevented us from being able to easily write applications in C++.  I definitely think better in C++ than in C, so this was a bummer. I was quite excited when the C++ issues were fixed in KSDK 1.2.  So now I need to port my application from C to C++.  At this point, I am faced with two hurdles: Directly porting my currently-working application (written for KDS 2 / KSDK 1.1) doesn't work.  I have written some posts here about it and could use some help solving those problems. lwIP project that was working in KDS 2.0 with MQX and PEx no longer works in KDS 3.0 How do you force PEx to be totally C++ compatible? Adding HardFault handlers in KDS3/KSDK1.2? Figuring out how to call into C++ wrappers This post is about #2, where I believe I have a usable solution.  It's basically covered in Re: How to call C functions that use "restrict" keyword from C ?  but with a small twist or two.  I am currently using KDS 3, KSDK 1.2, and my project requires MQX Standard as well as Processor Expert.When you create a project like mine, you will likely go through the following basic steps: Create new project Enable KSDK and Processor Expert Change osa from BareMetal to MQX Change MQX from Lite to Standard Disable DbgCs1 Enable new fsl_uart in MQX settings and disable its pins Add OS_Task components and other PEx components Specify your CPU type in the C++ compiler settings, as shown below Generate code In addition to main.c, after you generate code, you'll also end up with os_tasks.c.  Your PEx components will have C code added to the Generated Code folder.  At this point, it should be possible to wrap components in C++ classes.  Tonight, I ran a simple test where I wanted one of my MQX tasks to blink an LED.  The LED blink code was wrapped in a simple C++ class, and in order to be able to create the C++ object to call into, you have to call it from C++ code! The solution ends up being pretty simple.  Rename main.c to main.cpp, and rename os_tasks.c to os_tasks.cpp.  Then generate code again.  Click on your Sources folder and hit F5.  You will see that main.c and os_tasks.cpp reappear, because they get re-created.  Right click on each of them and click Resource Configuration -> Exclude from Build. Click Select All, then Close.  This will prevent those files from being compiled.  Note that if you add more OS_Task components, you will need to manually update os_tasks.cpp accordingly. At this point, it's very simple to create a wrapper class and call it.  I wrote one called DebugLed.cpp: #include <DebugLed.h> #include "Cpu.h" #include "gpio_comp.h" namespace Peripherals { DebugLed::DebugLed() {   // TODO Auto-generated constructor stub } DebugLed::~DebugLed() {   // TODO Auto-generated destructor stub } void DebugLed::BlinkGreen() {   GPIO_DRV_SetPinOutput( LEDRGB_GREEN);   OSA_TimeDelay(150);                 /* Example code (for task release) */   GPIO_DRV_ClearPinOutput( LEDRGB_GREEN);   OSA_TimeDelay(150);                 /* Example code (for task release) */ } } /* namespace Peripherals */ (hopefully all of the code shows up when I post this!  I don't see all of it in the preview) Then you can instantiate the DebugLed object before the while(1) in your OS_Task: void Blink_task(os_task_param_t task_init_data) {   /* Write your local variable definition here */   Peripherals::DebugLed led; #ifdef PEX_USE_RTOS   while (1) { #endif     /* Write your code here ... */    led.BlinkGreen(); #ifdef PEX_USE_RTOS     } #endif    } /* END os_tasks */ #ifdef __cplusplus }  /* extern "C" */ #endif Build, debug, and set a breakpoint on your call into your C++ object, and it should hit it! It's a lot easier than I thought it would be.  I figured there would be more manual labor involved with the code generation aspect of it, but it seems to basically boil down to two files, and you don't even need to disable code generation for any of the PEx components, which means you can still use the GUI to change settings if necessary (even though manually changing the header is just as simple). When I get to the office tomorrow, I'll probably start wrapping more complex peripherals, but I really need to figure out the HardFault problem with my lwIP project.  If you have any suggestions, please visit my post: Adding HardFault handlers in KDS3/KSDK1.2? and comment if you can.  I hope my first document here on the Freescale Community was helpful to someone here!
記事全体を表示
This document shows the implementation of the infrared on the UART0 using the FRDM-KE02Z platform. The FRDM-KE02Z platform is a developing platform for rapid prototyping. The board has a MKE02Z64VQH2 MCU a Kinetis E series MCU which is the first 5-Volt MCU built on the ARM Cortex-M0+ core. You can check the evaluation board in the Freescale’s webpage (FRDM-KE02Z: Kinetis E Series Freedom Development Platform) The Freedom Board has a lot of great features and one of this is an IrDA transmitter and receiver on it. Check this out! One of the features of the MCU is that the UART0 module can implement Infrared functions just following some tricks (MCU-magic tricks). According to the Reference Manual (Document Number: MKE02Z64M20SF0RM) this tricks are:      UART0_TX modulation: UART0_TX output can be modulated by FTM0 channel 0 PWM output      UART0_RX Tag: UART0_RX input can be tagged to FTM0 channel 1 or filtered by ACMP0 module For this example we are going to use the ACMP0 module to implement the UART0_RX functionality. Note1: The Core is configured to run at the maximum frequency: 20 Mhz Note2: Refer to the reference manual document for more information about the registers. Configuring the FTM0. The next lines show the configuration of the FTM0; the module is configured with a Frequency of 38 KHz which is the ideal frequency for an infrared led. The FTM0_CH0 is in Edge_Aligned PWM mode (EPWM).           #define IR_FREQUENCY       38000 //hz      #define FTM0_CLOCK                BUS_CLK_HZ      #define FTM0_MOD_VALUE            FTM0_CLOCK/IR_FREQUENCY      #define FTM0_C0V_VALUE            FTM0_MOD_VALUE/2      void FTM0CH0_Init( void )      {        SIM_SCGC |= SIM_SCGC_FTM0_MASK;             // Init FTM0 to PWM output,frequency is 38khz        FTM0_MOD= FTM0_MOD_VALUE;        FTM0_C0SC = 0x28;        FTM0_C0V = FTM0_C0V_VALUE;        FTM0_SC = 0x08; // bus clock divide by 2      } With this we accomplish the UART0_TX modulation through a PWM on the FTM0_CH0. Configuring the ACMP0. The configuration of the ACMP0 is using a DAC and allowing the ACMP0 can be driven by an analog input.      void ACMP_Init ( void )      {        SIM_SCGC |= SIM_SCGC_ACMP0_MASK;        ACMP0_C1 |= ACMP_C1_DACEN_MASK |                   ACMP_C1_DACREF_MASK|                   ACMP_C1_DACVAL(21);    // enable DAC        ACMP0_C0 |= ACMP_C0_ACPSEL(0x03)|                            ACMP_C0_ACNSEL(0x01);        ACMP0_C2 |= ACMP_C2_ACIPE(0x02);  // enable ACMP1 connect to PIN        ACMP0_CS |= ACMP_CS_ACE_MASK;     // enable ACMP                } With this we have now implemented the UART0_RX.     IrDA initialization. Now the important thing is to initialize the UART0 to work together with these tricks and implement the irDA functions. Basically we initialize the UART0 like when we use normal serial communication (this is not the topic of this post, refer to the project to see the UART_init function) and we write to the most important registers:         SIM_SOPT |= SIM_SOPT_RXDFE_MASK; UART0_RX input signal is filtered by ACMP, then injected to UART0.      SIM_SOPT |= SIM_SOPT_TXDME_MASK; UART0_TX output is modulated by FTM0 channel 0 before mapped to pinout. The configuration is as follows:      void IrDA_Init( void )      { // initialize UART0, 2400 baudrate        UART_init(UART0_BASE_PTR,BUS_CLK_HZ/1000,2400);                  // clear RDRF flag        UART0_S1 |= UART_S1_RDRF_MASK;                  // initialize FTM0CH1 as 38k PWM output        FTM0CH0_Init();                      // enable ACMP        ACMP_Init(); SIM_SOPT |= SIM_SOPT_RXDFE_MASK;  //UART0_RX input signal is filtered by ACMP, then injected to UART0.        UART0_S2 &= ~UART_S2_RXINV_MASK;  //inverse data input SIM_SOPT |= SIM_SOPT_TXDME_MASK;  //UART0_TX output is modulated by FTM0 channel 0 before mapped to pinout.      } With the irDA initialization we got the infrared features on the UART0. Philosophy of the Example In the attachments of this post you can find the example which shows the use of these functions in a basic application; the project was compiled in CodeWarrior 10.6 and the philosophy is: I hope that the information presented on this document could be useful for you. Thank you! Best Regards!
記事全体を表示
Hello, I've created a application of USB FLASH Drive acessing the 1MB internal FLASH of K64 using the Freescale's bareboard USB Stack 5.0 software + FRDM-K64F to be used by anyone as reference. It seems to be stable, I already wrote some files on that and checked the integrity of the volume. It can be very useful for datalogger application where the equipment can store data on the MCU FLASH using a internal filesystem, and read it through PC as it was a regular USB stick. It also very much cheaper than using a external SD Card, as it only needs the MCU + a external crystal and a USB connector.The only limitation so far is that it cannot exceed the number of the erase/write cycles of the device (of course!). Please see the file attached with the USB Stack and the example on the folder "{Installation Path}\Freescale_BM_USB_Stack_v5.0\Src\example\device\msd\bm\iar\dev_msd_disk_frdmk64f". The project was wrote using IAR. Also I have attached the srec file if you don't want to build the project by yourself. Any issues, doubts or suggestions, please let me know. Denis
記事全体を表示
This is an adaptation I made for the original SMTP protocol implementation provided with the KSDK1.3, with the addition of the secure connection using WolfSSL. The example software is currently ported to the FRDM-K64F Kinetis board but it can be implemented for other boards.This demo sends a e-mail using the Gmail SMTP server ( smtp.gmail.com , port 465) through a SSL channel.   How to run the example:   1 - Download the example software attached. You will need to have KDS 3.0 and KSDK1.3 previously installed on the machine. 2 - In KDS, go to File -> Import, select the folder Project of Projects -> Existing Project Sets, then open the file mqx_smtp_ssl_demo.wsd located in the folder \SMTP_SSL_demo_KSDK_1.3.0\examples\frdmk64f\demo_apps\security\smtp_wolfssl\smtp_wolfssl_mqx\kds 3- Build all the libraries and run the example project. 4- To allow SMTP + SSL , you will need to change your Gmail account settings 5- Using a Serial terminal (115200 bps,8N1) connected to the OpenSDA CDC interface (COM port), connect it to see the shell.Type ipconfig init and ipconfig dhcp to init the Ethernet interface and get a valid IP from the router.   6- Type help to see all the commands available. 7- To send a e-mail using the secure channel, you will need a valid gmail account and use the command:        sec_email -f <sender@email.com > -t <recipient@email.com> -s <www.mail.server.com> [-u <Username>] [-p <Password>] [-j <"email subject">] [-m <"text of email message"]>   For example:        sec_email -f user@gmail.com -t recipient@email.com -s smtp.gmail.com -u user@gmail.com -p mypassword -j "email subject" -m "text of email message"   Some additional notes:   - The Certificate Authority (CA) file from Equifax, used for Gmail, is decoded in hexadecimal to a c array and it is located in the file rtcs_smtp_ssl.c , in the \middleware\tcpip\rtcs\source\apps folder:     - To connect to other servers with SSL support, you will need to obtain a valid Certificate Authority file for this server. You can do it in three steps: 1) Verify what is the certificate authority used by the server. One way to do it is using OpenSSL ( OpenSSL  ) ,  with s_client and the option -showcerts to see the server certificates and check the certificate Authority.Gmail uses Equifax as CA 2) After you know the Certificate Authority of the server, you can get the certificate file in pem file format on a e-mail client for PC (e.g. Outlook).In this case , Outlook has the Equifax certificate file.All the certificate files need to start with -----BEGIN CERTIFICATE----- and to finish with -----END CERTIFICATE----- ,as below 3) You need to convert your CA file to a c language array. You can use Bin2h to do the task.        PEM file generated by Equifax before to be converted to a c array   All the files used to build the demo are included on the file attached. The SSL connection using the WolfSSL software is made on the file rtcs_smtp_ssl.c.
記事全体を表示
Hi All, I designed one multi-uarts bootloader project for customers, with which the customers can improve their production efficency in factory. The attached files is the host machine and slave machine bootloader programs and a document for reference. Now the programs can work smoothly on K64 freedom board with three uarts broadcust function. Anybody who has such request can refer to my new program. Best regards David
記事全体を表示