Skip navigation

/*
* SPI_FLASH_WRITE_READ
* SPI FLASH : MX25L16xx
* Author : wjandsq@163.com
* Date : 2020/06/28
*/
void SPI_FLASH_WRITE_READ(uint8_t *txdata_p, uint8_t * rxdata_p, uint8_t size)
{
uint32_t lpspi_tmp;
uint16_t i,j;
uint32_t words;
uint32_t remain_words;
uint32_t remain_bytes;

lpspi_tmp = size * 8;
words = lpspi_tmp / 32;
if (lpspi_tmp % 32) {
remain_bytes = size - words * 4;
words = words + 1;
}
remain_words = words;

#if 1
/* 2020/06/29 LPSPI1 Initialization for SPI_FLASH_WRITE_READ */
LPSPI1->CFGR1 = 0x00000003; /* MASTER、SAMPLE Set */
LPSPI1->FCR = 0x00000002; /* RXWATER=0 TXWATER=2 */
LPSPI1->CR = 0x00000009; /* Module Enable、Debug Enable */
LPSPI1->TCR = ((LPSPI1->TCR) & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK));

LPSPI1->SR |= LPSPI_SR_MBF_MASK;
if((LPSPI1->SR >> LPSPI_SR_MBF_SHIFT) & 1U) {
/* Module Busy flag or Hardware wrong */
for (i = 0, j = 0; i < 1000; ++i) {
if((LPSPI1->SR >> LPSPI_SR_MBF_SHIFT) & 1U) {
j = 1;
} else {
j = 0;
break;
}
}
if (j == 1) {
/* Over time Reset Receive FIFO、Reset Transmit FIFO */
LPSPI1->CR |= 0x00000030; /* Reset Receive FIFO、Reset Transmit FIFO */
}
} else {
/* Read Module Busy flag */
for (i = 0, j = 0; i < 1000; ++i) {
if((LPSPI1->SR >> LPSPI_SR_MBF_SHIFT) & 1U) {
j = 1;
} else {
j = 0;
break;
}
}
/* Module Busy flag */
if(j == 1) {
/* Over time Reset Receive FIFO、Reset Transmit FIFO */
LPSPI1->CR |= 0x00000030; /* Reset Receive FIFO、Reset Transmit FIFO */
}
}
#endif

/* Clean RX and TX buffers */
lpspi_tmp = (0x01 << LPSPI_CR_RRF_SHIFT) | (0x01 << LPSPI_CR_RTF_SHIFT) ;
LPSPI1->CR |= lpspi_tmp;

/* The second flush command is used to avoid the case when one word is still in shifter. */
lpspi_tmp = (0x01 << LPSPI_CR_RRF_SHIFT) | (0x01 << LPSPI_CR_RTF_SHIFT) ;
LPSPI1->CR |= lpspi_tmp;

LPSPI1->TCR = ((LPSPI1->TCR) | (LPSPI_TCR_BYSW_MASK)); /* 大小端字节交换 */

LPSPI1->SR |= 0x00003F00U; /* Clear all interrupts Flag */

/* if TX FIFO < FCR[TXWATER] Transmit data */
for (i = 0; i < words; ) {
if (remain_words > 2) {
while(((LPSPI1->SR & LPSPI_SR_TDF_MASK) >> LPSPI_SR_TDF_SHIFT) == 0);
LPSPI1->TDR = (uint32_t)(*(const uint32_t *)(txdata_p));
LPSPI1->SR |= LPSPI_SR_TDF_MASK; /* Clear TDF flag */
LPSPI1->TCR = ((LPSPI1->TCR) & (~LPSPI_TCR_RXMSK_MASK));
while(((LPSPI1->SR & LPSPI_SR_RDF_MASK) >> LPSPI_SR_RDF_SHIFT) == 0);
*(uint32_t *)(rxdata_p) = LPSPI0->RDR;
LPSPI1->SR |= LPSPI_SR_RDF_MASK; /* Clear RDF flag */
txdata_p += 4;
rxdata_p += 4;
--remain_words;
++i;
} else if (remain_words == 2) {
/* 5 byte、 6 bytes、7 bytes、 8 bytes Transmit and Receive test is OK 20200628 */
/* Set Frame_Size from 40bit、 48bit、 56bit、64bit */
lpspi_tmp = remain_bytes * 8 + 31;
LPSPI1->TCR = ((LPSPI1->TCR) | (lpspi_tmp & LPSPI_TCR_FRAMESZ_MASK));
LPSPI1->SR |= 0x00003F00U;
lpspi_tmp = (*(const uint32_t *)(txdata_p));
txdata_p = txdata_p + 4;
while(((LPSPI1->SR & LPSPI_SR_TDF_MASK) >> LPSPI_SR_TDF_SHIFT) == 0);
LPSPI1->TDR = lpspi_tmp;
LPSPI1->SR |= LPSPI_SR_TDF_MASK;
lpspi_tmp = (*(const uint32_t *)(txdata_p));
txdata_p = txdata_p + 4;
while(((LPSPI1->SR & LPSPI_SR_TDF_MASK) >> LPSPI_SR_TDF_SHIFT) == 0);
LPSPI1->TDR = lpspi_tmp;
LPSPI1->SR |= LPSPI_SR_TDF_MASK; /* Clear TDF flag */

while(((LPSPI1->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT) != 2);
lpspi_tmp = LPSPI1->RDR;
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 24) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 16) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 8) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 0) & 0x000000FF);
lpspi_tmp = LPSPI1->RDR;
for (j = 0; j < remain_bytes; ++j) {
*rxdata_p++ = (uint8_t)(lpspi_tmp >> (24 - j * 8));
}
LPSPI1->SR |= LPSPI_SR_RDF_MASK; /* Clear RDF flag */
while(((LPSPI1->SR & LPSPI_SR_FCF_MASK) >> LPSPI_SR_FCF_SHIFT) == 0);
LPSPI1->CR = 0x00000000; /* Module Disable、Debug Disable */
/* PCS Software Control to LOW */
i += 2;
} else {
if (remain_words == 1) {
/* 4 byte Transmit and Receive test is OK 2020/06/29 */
lpspi_tmp = 31;
} else {
lpspi_tmp = remain_bytes * 8 - 1;
}
LPSPI1->TCR = ((LPSPI1->TCR) | (lpspi_tmp & LPSPI_TCR_FRAMESZ_MASK));
LPSPI1->SR |= 0x00003F00U;
lpspi_tmp = (*(const uint32_t *)(txdata_p));
txdata_p = txdata_p + 4;
while(((LPSPI1->SR & LPSPI_SR_TDF_MASK) >> LPSPI_SR_TDF_SHIFT) == 0);
LPSPI1->TDR = lpspi_tmp;
LPSPI1->TCR = ((LPSPI1->TCR) & ~(LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_RXMSK_MASK));
LPSPI1->SR |= LPSPI_SR_TDF_MASK; /* Clear TDF flag */
while(((LPSPI1->SR & LPSPI_SR_RDF_MASK) >> LPSPI_SR_RDF_SHIFT) == 0);
lpspi_tmp = LPSPI1->RDR;
while(((LPSPI1->SR & LPSPI_SR_FCF_MASK) >> LPSPI_SR_FCF_SHIFT) == 0);
// while(((LPSPI1->SR & LPSPI_SR_WCF_MASK) >> LPSPI_SR_WCF_SHIFT) == 0); /* code with bug */
LPSPI1->SR |= LPSPI_SR_RDF_MASK; /* Clear RDF flag */
LPSPI1->CR = 0x00000000; /* Module Disable、Debug Disable */
/* PCS Software Control to LOW */
if (remain_words == 1) {
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 0) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 8) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 16) & 0x000000FF);
*rxdata_p++ = (uint8_t)((lpspi_tmp >> 24) & 0x000000FF);
} else {
for (j = 0; j < remain_bytes; ++j) {
*rxdata_p++ = (uint8_t)(lpspi_tmp >> (j * 8));
}
}
--remain_words;
++i;
}
}

#if 1
/* Recovery Setup For SDK API 2020/06/29 */
LPSPI1->TCR = ((LPSPI1->TCR) | (LPSPI_TCR_CONT_MASK));
LPSPI1->CFGR1 = 0x00000001; /* MASTER Enable、 SAMPLE Disable */
LPSPI1->FCR = 0x00000002; /* RXWATER=0 TXWATER=2 */
LPSPI1->CR = 0x00000000; /* Module Disable、Debug Disable */
#endif
}

The internal clock frequency of Kinetis chips varies due to manufacturing tolerances. A trim value is programmed into the chips to compensate for this variance and make the slow bus frequency uniform between chips.

 

For some inexplicable reason, this trim value is not active during debug mode. This makes developing serial and CAN applications very difficult, as the baud rates which are set are not the baud rates which are achieved. To make matters worse, if I understand the documentation correctly, the baud rate in debug mode is different from the baud rate in normal mode.

 

I am working with KDS and USBDM which makes a beautiful IDE and works with processor expert. Unfortunately KDS is no longer under development and S32 does not support processor expert for my chips. Porting over to a newer development environment might help with the clock frequency issues, but with existing projects and code bases that is not an attractive solution. Perhaps some of these problems do not occur with commercial software or have been resolved in MCU Expresso and S32 design studio.

 

So, to fix this clock issue with KDS perform the following.

Load the trim value from memory you can control

Figure 1: The processor expert tab with the processor selected

Figure 1: The processor expert tab with the processor selected

 

Go to the processor expert tab and click on your processor. In my case the processor is a SKEAZN64MLC2.

 

Figure 2: Adding code to initialize trim values from known memory locations

Figure 2: Adding code to initialize trim values from known memory locations

Maximize the component inspector so that you can see all the settings. Click on the Advanced tab, and put a check mark in the “Initialize slow trim value” box.

 

Clicking the “Initialize slow trim value” box writes the following code in the generated file CPU.c in order to load the trim value from addresses 0x3FE and 0x3FF.

 

if ( *((uint8_t*) 0x03FFU) != 0xFFU) {

ICS_C3 = *((uint8_t*) 0x03FFU);

ICS_C4 = (ICS_C4 & 0xFEU) | ((*((uint8_t*) 0x03FEU)) & 0x01U);

}

 

That part was easy.

 

Create linker memory description for locations 03FE and 03FF.

Figure 3: Adding a memory section for the values to be initialized.

Figure 3: Adding a memory section for the values to be initialized.

Still in processor expert with your processor selected, go to the build options tab and select Generate linker file. If the check box for "Generate linker file" is not checked check it (after saving your linker file by checking it into git so that you can compare changes and restore any prior modifications). Add a Rom/Ram area by clicking on the “+” button—my new section is called “m_init_clks_debug”. Set the qualifier to RX so the linker knows it is for flash memory. Since memory is in 4 byte units on this chip, set it at address 0x3FC and make it 4 bytes long.

 

Adding the line to the ROM/RAM areas in the CPU component declares a memory location for a new section by adding the line

m_init_clks_debug (RX) : ORIGIN = 0x000003FC, LENGTH = 0x00000004

to the linker file ProcessorExpert.ld,

Initialize the memory locations.

Figure 4: Initializing the memory location values.

Figure 4: Initializing the memory location values.

 

Go to the Build-options tab and select the filter User initialization. Click the three dots next to User data declarations to brings up a dialog where data declaration code can be written. Fill in the dialog with

 

const __attribute__ ((section (".init_clks_debug"))) uint8_t dbg_clk_init[4] =

{

0x00,

0x00,

0x00,

0x9A

};

 

to create an array "dbg_clck_init[4]" in section ".init_clks_debug" and initialize its values in memory. The value 0x9A is the trim value, which will be unique for each chip.

 

Code written in the “User data declarations” dialog box is written in the beginning of the CPU.c file every time the component is regenerated. If you add the code manually to the CPU.c file, the code will be erased each time the file is regenerated.

 

Make the ".init_clks_debug" section in the linker file.

Figure 5: Editing the processor expert linker file

Figure 5: Editing the processor expert linker file

 

I have found no way to do this through processor expert, so generate your processor expert code to add all the changes made in the earlier steps into your generated c code. Then go back to the <Processor Expert> <Build Options><Generate linker file> tab (Figure 3) and un-check the “Generate linker file” check box. This will prevent further modification of your linker file, and allow you to create the necessary section manually.

 

Open the linker file and add the following code to create the necessary section to put your initialized dbg_clk_init array into.

.init_clks_debug :

{

dbg_clk_init = .;

. = ALIGN(4);

KEEP(*(.init_clks_debug )) /* Startup code */

. = ALIGN(4);

} > m_init_clks_debug

 

Determine the proper trim value for your unique chip.

Figure 6: Finding the trim value

Figure 6: Finding the trim value

 

So far, it has worked for me to set a break point at the beginning of the code that was added to the Cpu.c file,

 if ( *((uint8_t*) 0x03FFU) != 0xFFU) {

ICS_C3 = *((uint8_t*) 0x03FFU);

ICS_C4 = (ICS_C4 & 0xFEU) | ((*((uint8_t*) 0x03FEU)) & 0x01U);

}

and to inspect the ICS.C3 and ICS.C4 registers in the EmbSys Registers tab of the debug perspective as in figure 6.

 

This begs the question—why was all this necessary? Before doing this work the value showing in ICS.C3 was 0x80, which may be some default? This caused to set baud rate of 36000 to give an actual baud rate of 38400 on one chip, something different on another chip. Worse yet, according to the documentation the baud rate is not the same in debug mode and normal operating mode. After making these modifications and programming the proper trim value, the set baud rate matches actual baud rate that the serial or CAN bus uses.

 

A further benefit is that you can program a non-standard value to set a non-standard baud rate if there is a need. From the data sheet:

 

ICS_C3 is automatically loaded during reset from a factory programmed location when not in a debug

mode. The factory programmed trim value adjusts the internal oscillator frequency to fint_ft as specified in

the datasheet. The user can provide a custom trim value to attain other internal reference clock

frequencies within the fint_t range. The custom trim value must be programmed into reserved flash

location 0x0000_03FF and copied to ICS_C3 during code initialization.

 

Each increase in the ICS.C3 setting lowers the frequency of the intermediate clock bus by approximately 100 cycles per second.

Ashok Ra

IMXRT Drum Pad

Posted by Ashok Ra May 29, 2020

Hi All,

This is Mini Drum Pad build in with IMXRT1015. Also it has AFE shield board which is used for capsense buttons.

IMX RT is, using SAI to play the audio file at 16KHZ. I have created 12 samples (.wav file) and the raw data is stored in the music file. Based on the capsense button press triggering the sound effect.

Speaker I used is from Boat, it has internal battery so only thing required is to feed the Aux input from IMXRT EVK.

I felt that, button sense over I2C bit slow due to that having the limitation of playing the music as faster. Anyway its just demonstration of my concept.

This drum has 3 modes of music set. The mode can be changed with the help of mechanical switch (push button). Also the volume can be controlled via Potentiometer.

For more details checkout here

The working video is here.

 

Thanks

Ashok R

https://ashokr.com

开发板是imx8M mini,我们自己做的板子,使用官方镜像yocto 4.14.98,OV5640 mipi摄像头,验证及其测试:

root@imx8mmevk:~# uname -a
Linux imx8mmevk 4.14.98-imx_4.14.98_2.0.0_ga+g5d6cbea #1 SMP PREEMPT Thu Dec 12 08:23:58 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux

 

我这里用的是I2C4的接口,所以设备树修改arch/arm64/boot/dts/freescale/fsl-imx8mm-evk.dts

&i2c4 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c4>;
    status = "okay";

    ov5640_mipi: ov5640_mipi@3c {
        compatible = "ovti,ov5640_mipi";
        reg = <0x3c>;
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_csi_pwn>, <&pinctrl_csi_rst>;
        clocks = <&clk IMX8MM_CLK_CLKO1_DIV>;
        clock-names = "csi_mclk";
        assigned-clocks = <&clk IMX8MM_CLK_CLKO1_SRC>,
                    <&clk IMX8MM_CLK_CLKO1_DIV>;
        assigned-clock-parents = <&clk IMX8MM_CLK_24M>;
                    assigned-clock-rates = <0>, <24000000>;
        csi_id = <0>;
        pwn-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
    //  rst-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
        mclk = <24000000>;
        mclk_source = <0>;
        port {
            ov5640_mipi1_ep: endpoint {

                 remote-endpoint = <&mipi1_sensor_ep>;
            };
        };
    };
};

I2C4、PWN、res等等引脚有占用,请把他们注释掉即可,内核默认是增加这个驱动的

  │ Symbol: MXC_CAMERA_OV5640_MIPI_V2 [=y]                                  │ 
  │ Type  : tristate                                                        │ 
  │ Prompt: OmniVision ov5640 camera support using mipi                     │ 
  │   Location:                                                             │ 
  │     -> Device Drivers                                                   │ 
  │       -> Multimedia support (MEDIA_SUPPORT [=y])                        │ 
  │         -> V4L platform devices (V4L_PLATFORM_DRIVERS [=y])             │ 
  │           -> MXC Camera/V4L2 PRP Features support

驱动不用修改,路径drivers/media/platform/mxc/capture/ov5640_mipi_v2.c

 

编译烧写开机,查看设备,可以发现如下信息,DOVDD等等找不到,应该是从imx6上移植过来的,imx8上这些引脚都已经用电路接好,不需要用程序控制,当然你也可以从设备树添加这些,不过没什么意义。我就把res-gpios添加,后来又加上没什么效果。上边设备树可以看到,我注释掉了。

root@imx8mmevk:~# dmesg |grep 5640
[    1.915242] ov5640_mipi 3-003c: No sensor reset pin available
[    1.921033] ov5640_mipi 3-003c: 3-003c supply DOVDD not found, using dummy regulator
[    1.928836] ov5640_mipi 3-003c: 3-003c supply DVDD not found, using dummy regulator
[    1.936552] ov5640_mipi 3-003c: 3-003c supply AVDD not found, using dummy regulator
[    3.103770] mxc_mipi-csi 32e30000.mipi_csi: Registered sensor subdevice: ov5640_mipi 3-003c
[    3.112716] ov5640_mipi 3-003c: Camera is found
root@imx8mmevk:~#

 

查看摄像头功能和信息,是vide0,YUYV格式

root@imx8mmevk:~# v4l2-ctl -D -d /dev/video0 --list-formats-ext
Driver Info (not using libv4l2):[  200.736512] ov5640_mipi 3-003c: Please assign pixel format, width and height

 Driver name   : mx6s-csi
 Card type     : i.MX6S_CSI
 Bus info      : platform:32e20000.csi1_bridge
 Driver version: 4.14.98
 Capabilities  : 0x84200001
  Video Capture
  Streaming
  Extended Pix Format
  Device Capabilities
 Device Caps   : 0x04200001
  Video Capture
  Streaming
  Extended Pix Format
ioctl: VIDIOC_ENUM_FMT
 Index       : 0
 Type        : Video Capture
 Pixel Format: 'YUYV'
 Name        : YUYV 4:2:2
  Size: Discrete 640x480
   Interval: Discrete 0.033s (30.000 fps)
  Size: Discrete 320x240
   Interval: Discrete 0.033s (30.000 fps)
  Size: Discrete 720x480
   Interval: Discrete 0.033s (30.000 fps)
  Size: Discrete 1280x720
   Interval: Discrete 0.033s (30.000 fps)
  Size: Discrete 1920x1080
   Interval: Discrete 0.033s (30.000 fps)
  Size: Discrete 2592x1944
   Interval: Discrete 0.067s (15.000 fps)
  Size: Discrete 0x0

root@imx8mmevk:~#

 

使用官方的指令测试,是可以显示到界面的,此时界面上有图像,没有什么问题哦。

root@imx8mmevk:~# gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-1920,height=1080 ! waylandsink
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
[  291.739794] ov5640_mipi 3-003c: s_stream: 1

 

然后我用自己写的V4L2程序采集,这里默认是采集的是YUYV图像,640*480,保存成 test-mmap.yuv格式,当然也可以让他自动转换成RGB显示在屏幕上,不过我还没有做。

root@imx8mmevk:~# ./wx

capabilities: 84200001
driver: mx6s-csi
card: i.MX6S_CSI
bus_info: platform:32e20000.csi1_bridge
version: 4.14.98

we are here11
{ pixelformat = 'YUYV', description = 'YUYV 4:2:2' }
we are here22
************** main, line = 139
we are here33
we are here44
we are here55
cjf__1
[  463.023861] ov5640_mipi 3-003c: s_stream: 1
buf.index dq is 0,
[  463.204929] ov5640_mipi 3-003c: s_stream: 0

root@imx8mmevk:~# ls -l
-rwxrwxrwx 1 root root  614400 Feb 20 20:31 test-mmap.yuv
-rwxrwxrwx 1 root root   23416 Feb 20 20:28 wx
root@imx8mmevk:~#

 

然后把文件拷贝出来,使用yuv工具打开查看,图像显示正常!希望对你们有帮助,谢谢!

Hello, recently I have done Periph Blinky e.g. from LPCOpen library on MCUxpresso. I am using LPC1769 chip and I have toggled GPIO pin. In my case I have used buzzer pin i.e. Port 3 & Pin 25. Instead of using Timer delay I created a delay function i.e. void delay_ms(unsigned int ms). Here I am attaching the systick.c file. Hope it helps!!  

Hello everyone, I am working on MCUxpresso and using LPC1769 controller. I am done with Led blinking in MCUxpresso. I have used flash magic to flash the hex file in controller using usb to ttl. But I faced a hex file issue while doing this project. So I thought I should share this with everyone who are facing the same issue. After compiling only .axf was getting created. For creating .hex file ,you need to do following settings:

 

1)Go to properties---> C/C++ Build --->Settings ---> Build Steps

 

Now in post build steps :

 

Change

 

arm-none-eabi-size "${BuildArtifactFileName}"

 

# arm-none-eabi-objcopy -v -O binary "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.bin"

 

# checksum -p ${TargetChip} -d "${BuildArtifactFileBaseName}.bin

 

to

 

arm-none-eabi-size "${BuildArtifactFileName}"

 

# arm-none-eabi-objcopy -v -O hex "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.hex"

 

# checksum -p ${TargetChip} -d "${BuildArtifactFileBaseName}.hex"

 

 

 

2) After  doing step 1, please check if axf is selected in Artifact extension as shown below:

 

 

 

 

3)For creating hex file go to Debug-->.axf file-->Right Click-->Binary Utilities-->Create hex. Now you are ready to flash! 

 

 

 

 

Also kindly check this article:MCUXpresso IDE: Creating Binary Files (S-Record, Intel Hex, Binary) 

 

 

 

After doing these settings I got the hex file and finally it worked!!

When you start a board bring up activity from scratch, there are many challenges. The first of these challenges is the choice of the development environment. Is there any commercial agreement with an IDE Vendor? How flexible is debugging on the IDE and build time, code footprint after optimization etc are related concerns. If the choice is a command line based build environment, the developer is free to choose what features he needs and how easily he can customize it for his requirements.

 

In case of a Graphical development environment, the IDE takes that decision for you. There are many Graphical IDEs some are commercially licensed and some are available with opensource licenses. Eclipse based IDEs are very famous across the opensource licensed Graphical IDEs.

 

Not just due to its extended support, flexibility and ease of use, but also because eclipse provides SDKs to auto generate code for quick application development, many semiconductor vendors(like NXP and Infineon) are giving eclipse based IDEs While I have worked with both commercial and opensource IDEs, my personal favorite has always been an eclipse based IDE. The following are some of the cool eclipse based tools that I have worked with:

  1. Infineon's DAVE is an eclipse based IDE which auto generates MISRA C compliant c code for low level drivers which are run on bare metal as well as on an RTOS for Infineon's micro controllers. Reference.
  2. Freescale's Processor expert is an eclipse plugin which generates C code for Freescale's microcontrollers for baremetal or RTOS(MQX, FreeRTOS, uCOSII) applications. Reference

 

 

The code generated here can be compiled with GCC(default), IAR or Tasking compilers.These are some reasons which make opensource Eclipse tools my favorite. Besides these, I always prefer my IDE to have the following features:

  1. Documentation extraction or generation from source code.
  2. Auto indentation,
  3. Auto complete option for variables, API, pre processor includes, etc.
  4. Performance analysis like code coverage
  5. Subversion control,
  6. Compare and Merge options for code references.

 

Eclipse based IDEs provide very easy interface or plugins for these features. Having said that, the custom board I had to bring up is Freescale MK64FX512 based microcontroller to run applications based on Freescale MQX 4.2 RTOS. MQX has a clearly defined structure as given in the following references:

Video Vault

Getting Started with MQX.

 

Briefly, to bring up the board with MQX RTOS:

  1. Identify the reference base board.
  2. If the base board configuration matches with your board hardware, go as is otherwise, customize the PSP(Processor Support Package) and BSP(Board Support Package) for your board and rebuild the PSP and BSP projects. The output is a library file for both these projects.
  3. Integrate the bsp.lib and psp.lib with the hello_world project given by MQX for all supported packages and configurations. While you can prepare a hello world project from scratch, picking up an existing project is easier and time saving.

I'll make a separate note on how to customize the BSP and PSP projects for custom hardware. This note is intended to describe the steps involved in the board bring up and customizing the development environment.

 

Here are the steps to bringup a Freescale K64 micro based custom board on MQX RTOS(Ver 4.2) on KDS IDE. My base board is TWR-K64. Yours can be a FRDM-K64 too which is very popular these days. I have taken the hello_world project in the example projects list for the bring up activity.

Add the following paths in the compiler-> include settings in settings page: "${workspace_loc:/${ProjName}/Includes/debug}"

"${workspace_loc:/${ProjName}/Includes/debug/bsp}"

"${workspace_loc:/${ProjName}/Includes/debug/psp}"

"${workspace_loc:/${ProjName}/Includes/debug/bsp/Generated_Code}"

"${eclipse_home}../toolchain/lib/gcc/arm-none-eabi/4.8.4/include"

"${eclipse_home}../toolchain/lib/gcc/arm-none-eabi/4.8.4/include-fixed"

"${eclipse_home}../toolchain/arm-none-eabi/include"

 

If you have any custom code or drivers or application codes, add their paths as follows: "${workspace_loc:/${ProjName}/}"

 

You can ensure that the firmware project is portable in this way as it avoids absolute links. Try to keep all all links relative to the work space or project location. Add the custom BSP and PSP libraries to Linker->Miscellaneous-> Other Objects as follows:

"${workspace_loc:/${ProjName}//bsp.a}"

"${workspace_loc:/${ProjName}//psp.a}"

 

Custom linker script can be added in Linker->General->Script Files as follows: "${workspace_loc:/${ProjName}//custom_linker_script.ld}"

 

Now build your application, clear the compiler issues and you are ready to go! Besides this, you can also add the Doxygen, Emsys register View plugins for documentation and debugging. Visit  this reference for more details on this.

 

Happy coding!

CSMG Sarma

MQX SPI Slave Configuration

Posted by CSMG Sarma Jun 11, 2018

I was surprised to learn MQX(Ver 4.2) does not support SPI Slave configuration.

Reference

There are many workarounds in the community but the information is in bits and pieces. So i decided to write this note.

I wanted to configure SPI0 Channel on MK64FX512VLQ12 board as Slave driven by interrupt in which can call MQX APIs. I have MQX Ver 4.2 installed.  My base BSP is derived from TWR-K64 board BSP given by MQX. IDE is KDS.f Reference hardware is TWR-K64 board. 

 

The options available are:

  1. Create your own Driver. Integrate it with BSP.
  2. Integrate Processor Expert generated code to your MQX application.
  3. Integrate(Enable) Processor Expert in your MQX Application.
  4. Integrate Legacy MQX SPI(Ver 3.6 or old) driver Code to your MQX application.

 

Initially I was hesitant of modifying the BSP. But now it looks to be the best option compared with the other options.

The files needed to be modified for SPI to work as Slave are:

1. user_config.c: I added the following lines here:   

/**
      * Custom BSP macros.
      * */

      #define BSPCFG_ENABLE_SPI0_SLAVE 1 //SPI0 as slave.
      #define SPI0_SLAVE_POLL 0
      /**
      * @see NVIC implementation on MQX for the following https://community.nxp.com/docs/DOC-335593
      * */

     //#define MQX_ROM_VECTORS 1

SPI0_SLAVE_POLL is set to 1 if SPI0 channel polls for data from Master. And set to 0 if interrupt are expected on every event of SPI Master sending data.

MQX_ROM_VECTORS is an MQX macro, define if you wish to have your ISR in the ROM address unlike the BSP registered ISR, which run from RAM. Breifly, this macro setting decide if you want to use _int_install_kernel_isr() or _int_install_isr() to register your ISR. See the following link for more details.

Reference

 

2. init_bsp.c: I added the following lines here:   

#if (BSPCFG_ENABLE_SPI0_SLAVE == 1)
      spi0_slave_init();
      #endif


Based on user_config.h, spi0_slave_init() would be called. Its definition looks like this:

     void spi0_slave_init(void)
      {
           SIM_MemMapPtr sim = SIM_BASE_PTR;
           PORT_MemMapPtr pctl;
          VDSPI_REG_STRUCT_PTR spi0_base = (void *)SPI0_BASE_PTR;
          /* GPIO init */
           pctl = (PORT_MemMapPtr)PORTD_BASE_PTR;
           /** 2 chipselects
                * Select whichever is needed for a Master. */

           pctl->PCR[0] = PORT_PCR_MUX(2); /* DSPI0.PCS0 */
          pctl->PCR[1] = PORT_PCR_MUX(2); /* DSPI0.SCK */
           pctl->PCR[2] = PORT_PCR_MUX(2); /* DSPI0.SOUT */
           pctl->PCR[3] = PORT_PCR_MUX(2); /* DSPI0.SIN */
          /* Enable clock gate to DSPI0 module */
           sim->SCGC6 |= SIM_SCGC6_SPI0_MASK;
          /* MCR Configuration */
           spi0_base->MCR = 0x00; //Overwrite the Default value of MCR.
          spi0_base->MCR |= DSPI_MCR_ROOE_MASK ;
          spi0_base->CTAR[0] = DSPI_CTAR_FMSZ(15); //frame size = 16 bits.
           spi0_base->RSER &= ~(DSPI_SR_TFFF_MASK); //TFFF flag generates Interrupt requests.
          /* Install Interrupts to BSP */
           if (SPI0_SLAVE_POLL == 0)
           {
                     spi0_base->RSER |= DSPI_RSER_TCF_RE_MASK; //generate Transmission complete requests.
            }
     }

This definition is in a new file I added to BSP. 


3. vectors.c: Replaced DEFAULT_VECTOR with spi0_slave_isr(my custom ISR) in __vector_table at SPI0_ISR location. It originally looked like this: 

  DEFAULT_VECTOR, /* 0x2A 0x000000A8 - ivINT_SPI0 */


Now its like this:

     spi0_slave_isr, /* 0x2A 0x000000A8 - ivINT_SPI0

This is useful if you are running the ISR from ROM. If you are registering your ISR to MQX, with will be over written. If ISR is not registered to MQX, then MQX APIs(like signalling events or posting semaphore) couldn't be used. So make your choice wisely.

 

4. <>_ISR.c: This file contains is my custom ISR handler for SPI0 interrupts which occur when data is received on SPI0 channel. This is file is part of my MQX application project and not BSP. The ISR looks as follows:

     #if (MQX_ROM_VECTORS == 1) //if bypassing kernel(BSP's) ISRs
      void spi0_slave_isr(void)
      {
     #else
      void spi0_slave_isr(void * parameter)
      {
      (void)parameter; //to satisify compiler.
     #endif
          static volatile uint8_t * r_buf; //= spi_slave_buffer.r_buf;
           static volatile uint8_t * w_buf; // = spi_slave_buffer.w_buf;
           static volatile uint8_t len; // = spi_slave_buffer.len_buf;

           LED_TOGGLE(&led_blue);

           if((spi0_base->SR & DSPI_SR_RFDF_MASK) == DSPI_SR_RFDF_MASK)
           {//Read RX FIFO
                test_flag |= SPI_RX_ISR;
                spi0_base->SR |= DSPI_SR_RFDF_MASK; /* clear the interrupt flag*/
           }
           else if((spi0_base->SR & DSPI_SR_TCF_MASK) == DSPI_SR_TCF_MASK)
           {//Transfer Complete Flag, Write to TX FIFO now
                test_flag |= SPI_TX_ISR;
                spi0_base->SR |= DSPI_SR_TCF_MASK; /* clear the interrupt flag*/
           }
          if (_lwevent_set(&lwevent_spi_slave, 0x01) == MQX_OK)
           {
                LED_TOGGLE(&led_green);
           }
      }

 

There is a task which is blocked waiting for the event it looks something like this:   

if ((test_flag & SPI_RX_ISR) == SPI_RX_ISR)
      {
           test_flag &= ~SPI_RX_ISR;
           spi_slave_buffer.r_buf[0] = (uint8_t)(DSPI_POPR_RXDATA_GET(spi0_base->POPR) & 0x00FF);
           spi_slave_buffer.r_buf[1] = (uint8_t)((DSPI_POPR_RXDATA_GET(spi0_base->POPR) >> 8) & 0x00FF);
           printf("\treceived 0x%x 0x%x\n", spi_slave_buffer.r_buf[0], spi_slave_buffer.r_buf[1]);

           res = spi_slave_buffer.r_buf[1];
           res |= (((uint32_t )spi_slave_buffer.r_buf[0]) << 8);
           spi0_base->SR |= DSPI_SR_TCF_MASK; //clear the TCF Flag.
           spi0_base->PUSHR = res; //write the data
      }
      else if((test_flag & SPI_TX_ISR) == SPI_TX_ISR)
      {
           test_flag &= ~SPI_TX_ISR;
          res = 0;
          while (spi_slave_buffer.len_buf > res)
           {
                spi0_base->PUSHR = spi_slave_buffer.w_buf[res];
                res++;
           }
           printf("\ttransmission complete\n");
      }
      else
      {
           printf("\tSomething's wrong with SPI0_Slave!!\n");
      }

I have tried this ISR be registering it to MQX as well as running it from ROM directly. If you want to run the ISR from ROM table you need to remove MQX APIs and ensure proper synchronization between ISR and the tasks(this is removed here for brevity).

 

With this, you are ready to go! To conclude, modifying the BSP for an interrupt driven SPI Slave driver is easier than any other option. Also there is no other documented description available. I had tried the other 3 options I mentioned at the beginning of this note. But ended up in loosing lot of time and no logical conclusion. Its unfortunate that MQX has not closed this issue which has been existing and known to them for so long.

 

Hope this helps.

 

PS: I have removed some of the lines for brevity and to keep the note simple. Don't panic!

 

Happy hacking!

Sarma

ramya sri

managed security services

Posted by ramya sri Apr 18, 2018

managed security services

The headlines are full of it, and more so every day. Security is everyone's concern, because a breach risks everything. For all its function and capacity, the Internet has in some ways become a less secure and reliable medium. Inadequate security can cost you customers, profits, your business and your future. ExterNetworks Managed Security Solutions protect you with a range of proprietary tools and processes to lessen the incessant onslaught of viruses, guard against outside intrusions that eliminate key system codes, and defend against the malicious commands they trigger.

/* ###################################################################
** Filename : main.c
** Processor : S32K144_100
** Abstract :
** Main module.
** This module contains user's application code.
** Settings :
** Contents :
** No public methods
**
** ###################################################################*/
/*!
** @file main.c
** @version 01.00
** @brief
** Main module.
** This module contains user's application code.
*/
/*!
** @addtogroup main_module main module documentation
** @{
*/
/* MODULE main */


/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "pin_mux.h"
#include "clockMan1.h"

volatile int exit_code = 0;
/* User includes (#include below this line is not maintained by Processor Expert) */

/*!
\brief The main function for the project.
\details The startup initialization sequence is the following:
* - startup asm routine
* - main()
*/
int main(void)
{
/* Write your local variable definition here */
uint32_t cycles;
uint8_t color;
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of Processor Expert internal initialization. ***/

/* Write your code here */
CLOCK_SYS_Init(g_clockManConfigsArr,FSL_CLOCK_MANAGER_CONFIG_CNT,g_clockManCallbacksArr,FSL_CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0,CLOCK_MANAGER_POLICY_FORCIBLE);

GPIO_HAL_SetPins(PTD,(1 << 15));
GPIO_HAL_SetPins(PTD,(1 << 16));
GPIO_HAL_SetPins(PTD,(1 << 0));

PINS_DRV_Init(NUM_OF_CONFIGURED_PINS,g_pin_mux_InitConfigArr);

GPIO_HAL_SetPinsDirection(PTD, ((1 << 15) | (1 << 16) | (1 << 0)));


GPIO_HAL_ClearPins(PTD,(1 << 15)); /* RED LED ON */
GPIO_HAL_SetPins(PTD,(1 << 15));
GPIO_HAL_ClearPins(PTD,(1 << 16)); /* GREEN LED ON */
GPIO_HAL_SetPins(PTD,(1 << 16));
GPIO_HAL_ClearPins(PTD,(1 << 0)); /* BLUE LED ON */
GPIO_HAL_SetPins(PTD,(1 << 0));

for(;;) {
cycles = 3600000;
while(cycles--);

asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");

switch(color){
case 0:
GPIO_HAL_ClearPins(PTD,(1 << 15));
GPIO_HAL_SetPins(PTD,(1 << 16));
GPIO_HAL_SetPins(PTD,(1 << 0));
break;
case 1:
GPIO_HAL_SetPins(PTD,(1 << 15));
GPIO_HAL_ClearPins(PTD,(1 << 16));
GPIO_HAL_SetPins(PTD,(1 << 0));
break;
case 2:
GPIO_HAL_SetPins(PTD,(1 << 15));
GPIO_HAL_SetPins(PTD,(1 << 16));
GPIO_HAL_ClearPins(PTD,(1 << 0));
color = 255;
break;
default:
GPIO_HAL_SetPins(PTD,(1 << 15));
GPIO_HAL_SetPins(PTD,(1 << 16));
GPIO_HAL_SetPins(PTD,(1 << 0));
color = 255;
break;
}
++color;
// GPIO_HAL_TogglePins(PTD, ((1 << 15) | (1 << 16)));
}
/* For example: for(;;) { } */

/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of RTOS startup code. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END main */
/*!
** @}
*/
/*
** ###################################################################
**
** This file was created by Processor Expert 10.1 [05.21]
** for the Freescale S32K series of microcontrollers.
**
** ###################################################################
*/

Dear friends,

 

I have been trying to test the can_ loop back_ node in KINETIS512_SC_100MHz.zip file by using flexcan1 in TWR-K60F120M module.I have used A47 & A48 primary elevator connections for flexcan1 as shown in freescale user guide. But i dont know how to test the CAN transmission by enabling loop back node .Could you please help to find the confiuration settings in TWR SER ,elevator and steps for how to send and receive messages??

 

Here i am attaching the testing code for flexcan

 

With Regards

Sruthy

Original Attachment has been moved to: HART_AO.zip