MQX Software Solutions Knowledge Base

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

MQX Software Solutions Knowledge Base

Discussions

Sort by:
When working on Cortex-M4 platform, an exception which has not been expected (an interrupt without ISR, an access to an illegal address, etc). The code below shows how to implement it. static void expt_frm_dump(pointer ext_frm_ptr) {   static char *expt_name[] = {     "None",     "Reset",     "NMI",     "HardFault",     "MemManage",     "BusFault",     "UsageFault",     "Rsvd",     "Rsvd",     "Rsvd",     "SVCall",     "Debug Monitor",     "Rsvd",     "PendSV",     "SysTick"   };   uint_32 excpt_num = __get_PSR() & 0x1FF;   printf("Opps, bad thing happened.\n");   if(excpt_num < 16){     printf("The exception [%s] invoked in TASK 0x%x\n",          expt_name[excpt_num] , _task_get_id());     printf("Dump the exception frame as :\n");     printf("R0:\t0x%08x\n", *((uint_32 *)ext_frm_ptr));     printf("R1:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 1));     printf("R2:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 2));     printf("R3:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 3));     printf("R12:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 4));     printf("LR:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 5));     printf("PC:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 6));     printf("PSR:\t0x%08x\n", *((uint_32 *)ext_frm_ptr + 7));   }else{     printf("The external interrupt %d occured while no handler to serve it.\n");   } } void  task_exception_handler(_mqx_uint para, pointer stack_ptr) {     pointer expt_frm_ptr = (pointer)__get_PSP();     expt_frm_dump(expt_frm_ptr); } void test_task(unsigned long para) {   unsigned int *p_bad = (unsigned int *)0;   printf("Install the _int_exception_isr to replace the _int_default_isr\n");   _int_install_exception_isr();   /* Set the exception handler of the task */   _task_set_exception_handler(_task_get_id(), task_exception_handler);   *p_bad = 0;     // an access to address 0    _task_block(); }
View full article
Q: I installed the MQX software release, but when I run a project, CodeWarrior can't find file x...  A: Symptom A project will build correctly, but when you run it, CodeWarrior asks you to locate files that it can't find. Solution: This problem is caused if you are running from a directory that is not the default directory that the installer placed the files. You just need to re-build the libraries. To build all MQX libraries at once, the special mass-build project may be used. The project is located together with the user_config.h file in directory: <install_dir>/config/<board>/build_libs.mcp. See the Release Notes for more details on building the libraries. Q: What software tools do I need for the MQX 3.0.0 demos and lab tutorials? A: The first release of Freescale MQX (3.0.0) requires CodeWarrior for ColdFire v7.1 Professional Edition (30-day evaluation available) to unlock the full potential of the demos and labs. Is version 7.1 necessary?  Yes, 7.1 contains the necessary support for M5225EVB and M52259DEMOKIT. What about CodeWarrior Special Edition?  Due to the code size limitation (<128k) of Special Edition, several lab demos will not compile/program.  These include MQX labs 3 and 4.  Also, Task Aware Debugging is not available in Special edition, therefore lab 5 is not possible.  Additionally, the targets which utilize the MRAM on the M52259EVB will not work. What about CodeWarrior Basic and Standard Edition? Task Aware Debugging is not available in Basic or Standard edition,therefore lab 5 is not possible.  Also, with Basic Edition the targets whichutilize the MRAM on the M52259EVB may not work. Q: I'm having trouble establishing an Ethernet connection between my PC and the board.  What do I do? A: 1) Hit the Reset button on the board after you plug in the cable.  2) Wait a minute or two for your computer to connect. Connect the board directly to your computer with an ethernet crossover cable.  You must wait a minute or two for your computer to try to aquire a network address.  Since you're no longer connected to your network the computer will eventually revert to an Auto IP address on the same subnet as board (169.254.x.x). 3) Disable your wireless router if you have one. 4) Disable proxy server settings in your web browser. Notes: When connected your computer might report limited or no connectivity, but it should still work. Ping is disabled in release 3.0.0, so pinging the board from the computer will not work. If all else fails, configure your IP address manually as instructed by the quick start guide. Q: Can I modify the webpages used in the webserver lab? A: Yes, there is a tool called MKTFS which can be used to convert web pages and images into a C array's, which are used by the MQX webserver.  Edit the webpages in the folder \demo\web_hvac\web_pages.  Then click on \demo\web_hvac\mktfs.bat.  The script will update the file tfs_data.c in the \demo\web_hvac folder.  When you recompile the hvac_web project and program it the new webpages will be loaded into memory.          Q: Can I use my own USB Flash drive in the labs? A: Yes, just copy over the files from the flash drive that is provided with the M52259EVB or M52259DEMOKIT. Q: My USB Flash drive doesn’t work, what should I do? A: Not all USB flash drive conform to the same specification and there are small differences between them that could cause some not to work.  It will say "Unable to open USB disk" at the terminal if the flash drive is not compatible. We are working to expand compatibility to as many usb flash drive manufactures and models as possible.  If you encounter one that does not work please perform the following tasks. Open up the project in <mqx install directory>/usb/host/examples/mass/msc_commands/codewarrior/ Load and run the project with the USB stick unattached. Then with the Terminal open and connected, plug in the non-functioning USB stick. A test will run automatically upon insertion of the USB stick.  The test will output useful information to the terminal that will help us. Please provide us the output that this test generates, along with the exact make and model of the USB flash drive.  We will create a thread on the forums that you can post this to. More info: Tested USB Stick Q: What are tasks and how are they created? A: Tasks share the same code space if they execute the same root function. A task always starts executing at the entry point of the root function even if the function is its creator’s root function. This is not the same behavior as fork() in UNIX. Q:Do I always need at least one autostart task? A: Yes. In an application, at least one autostart application task is required in order to start the application. In a multiprocessor application (the application can create tasks remotely), each image need not have an autostart application task; however, each image must include IPC Task as an autostart task in the task template list. If no application task is created on a processor, Idle Task runs. Q:How much stack space should I give to various tasks in my application? A: This is a really hard question to answer as the amount of stack space is extremely application specific. Different tasks will need varying amounts of stack space depending on the job they are trying to perform. We usually recommend starting all (or most) of tasks with plenty of stack memory (double or triple what you think they would need) and then later optimizing the system with TAD (Task Aware Debugging module). Q: How do I dynamically alter the task stack size? A: In a situation where a task runs a while and then blocks. In it's blocked state, it holds a couple of event connections which are used by interrupts, but otherwise needs no stack space. One would like to reduce the stack space being used by the task in its blocked state. How do you do this? If the task is never going to run again, the user could _mem_free or better yet _mem_free_part on the stack. Using _mem_free_part will not cause some of our tools to complain. In the task whose stack to be freed, the very first thing it does is to save the value of kernel_data->ACTIVE_PTR->MEMORY_RESOURCE_LIST; /* Global var */ pointer stack_ptr; { /* In task */ KERNEL_DATA_STRUCT_PTR kernel_data = _mqx_get_kernel_data(); /* Do this very first thing */ stack_ptr = kernel_data->ACTIVE_PTR->MEMORY_RESOURCE_LIST; /* Rest of code for task */ } { /* some other task*/ _mem_free(stack_ptr); } Q:How does MQX™ measure a timeslice? Is the timeslice absolute or relative? That is, if a task has a 10-ms timeslice and starts at time=0 ms, does it give up the processor at time=10 ms, or does it give up the processor after 10 ms of execution? A: With a 10-ms timeslice, MQX counts the number of periodic timer interrupts that have occurred while the task is active. If the equivalent of 10 or more milliseconds have expired, MQX effectively runs _sched_yield() for the task. As a result, a task does not get 10 ms of linear time since higher-priority tasks will preempt it. Also, if the task calls a scheduling service (for example _task_block() or _sched_yield()), MQX sets the task’s timeslice counter back to zero. As with timeouts, the time that MQX allocates is plus or minus BSP_ALARM_RESOLUTION. Q: How do I increase TCP performance? A: Increase the size of the send and/or receive windows. Send data in multiples of the maximum segment size (MSS). Disable the Nagle algorithm. Q: Is there a limit to the number of sockets that can be created with RTCS? A: No. Sockets come from a partition with an infinite growth factor, so the number of sockets is limited only by the available memory on the board. Q: Do I always need at least one autostart task? A: Yes. In an application, at least one autostart application task is required in order to start the application. In a multiprocessor application (the application can create tasks remotely), each image need not have an autostart application task; however, each image must include IPC Task as an autostart task in the task template list. If no application task is created on a processor, Idle Task runs. Q: Is it possible to rename a task after it is created? A: Here's a function to get a pointer to the task's template struct where the task's name is stored. The function needs a couple of structures from mqx_prv.h.Namely, TD_STRUCT and KERNEL_DATA_STRUCT. You can add the function to your application or add it into MQX itself. If you are adding it to app, you will need to include "mqx_inc.h" and add mqx\source\include to the compiler's include search path. /*FUNCTION*-------------------------------------------------------------------* * Function Name : _task_get_template_ptr* Returned Value : TASK_TEMPLATE_STRUCT_PTR* Comments :* Returns a pointer to the task's template structure* *END*----------------------------------------------------------------------*/TASK_TEMPLATE_STRUCT_PTR _task_get_template_ptr(_task_id){ /* Body */  KERNEL_DATA_STRUCT_PTR kernel_data;  TD_STRUCT_PTR td_ptr;  _GET_KERNEL_DATA(kernel_data);  if (task_id == MQX_NULL_TASK_ID) {    td_ptr = kernel_data->ACTIVE_PTR;  } else {    td_ptr = (TD_STRUCT_PTR)_task_get_td(_task_id);  } /* Endif */  if (td_ptr) {    return( td_ptr->TASK_TEMPLATE_PTR );  } /* Endif */  return( NULL );} /* Endbody */An example of how to use this function:/* Need prototype */extern TASK_TEMPLATE_STRUCT_PTR _task_get_template_ptr(_task_id);..../* Dynamically create the task */some_task_id = _task_create(..... );.../* Change name of some_task */template_ptr = _task_get_template_ptr(some_task_id);template_ptr->TASK_NAME = "new name";../* Change name of the current (active) task */template_ptr = _task_get_template_ptr(MQX_NULL_TASK_ID);template_ptr->TASK_NAME = "new name"; Q: How are exceptions or unhandled interrupts handled by MQX? A: Basically, there are three ways of handling unhandled interrupts. They are mutually exclusive - in other words, you can only have one active at a time. You'd pick the one that best suits you for an application and use it: 1) _int_default_isr() This is the default mode of handling interrupts - it simply blocks the offending task and sets its state to "Unhandled Interrupt Blocked" 2) _int_unexpected_isr() This mode can be activated by calling _int_install_unexpected_isr() from the application. This will also block the offending task and set its state, but also will print some info on the console about who and what caused the unexpected exception 3) _int_exception_isr() This is the most functional (but also most complex) of all the modes. It can be activated by calling _int_install_exception_isr(). Once this is installed, any unhandled interrupts will call _int_exception_isr(). It might help you understand the behavior of this function by actually looking at the code. It's in source\psp\\int_xcpt.c. Here are the comments that define the behavior: If an exception happens while a task is running, then: if a task exception handler exists, it is executed, otherwise the task is aborted. If an exception happens while an isr is running, then: if an isr exception handler exists, it is executed, and the isr aborted otherwise the isr is aborted. This is why you have to provide exception handlers. For tasks, you install these with _task_set_exception_handler(). You would need to install a handler for each task in your system that you want handled (conceivably, this could be the same handler for all of them) For ISRs, you install these with _int_set_exception_handler(). The parameter is the vector number of the interrupt your installing a handler for, not the exception vector itself (in other words, you'd install handlers for the vectors of ethernet, UARTs, timers, etc, not the divide by zero vector) So, if you want to have full "handling" of all unhandled interrupts, you'll have to install handlers for all the tasks and ISRs that exist in your system. The handler itself could simply flag the error and allow the task to continue running. Other comments: -Note that you shouldn't have to rebuild MQX libraries to change the modes - its simply done with a function call -If one of the above three methods of handling unhandled interrupts does not suit you, you can also create your own handler to take whichever action you want and install it by calling _int_install_default_isr() with your own ISR as a parameter. This might be a simpler approach than using the exception handlers. Q:How is DNS enabled? A:Include DNS.H in the application. Call DNS_init() after calling RTCS_create(). Then insert the following code: DNS_First_Local_server[0].IP_ADDR = "my dns server's ip addr"; Q:Does MQX have memory protection? A: No, not full memory protection (this allows us to run the same code on CPUs -- like DSPs -- without MMUs). However, we do have a version of MQX with some level of MMU support. It allows simple memory protection between tasks and is available for some PowerPC derivatives. Q:What happens if Idle Task blocks because of an exception? A: If Idle Task blocks, System Task, which is really a system task descriptor that has no code, becomes the active task. System Task Descriptor sets up the interrupt stack; then re-enables interrupts. As a result, the application can continue to run. Q:If more than one task "owns" a semaphore, and a priority boost is required, do all owning tasks have their priority raised, or just one? A: The owning task with the highest priority gets boosted. Q:In many RTCS examples we find "/* Enable IP forwarding */ _IP_forward = TRUE;". What does this do? A: This enables forwarding of IP packets from one interface to another. If you have two Ethernet connections, this allows RTCS to route packets between the two interfaces. Q:How do we setup Ethernet auto-negotiation? A:Normally, this is done in the file enet_ini.c, located in the BSP (source/bsp), and normally autonegotiate is the default. Sometimes (but not always) the flag passed to enet_initialize is passed down to this function, and is used to select autonegotiate. Q:How do I bind a UDP socket to a specific IP address and have it receive broadcast packets? A: RTCS does not allow UDP sockets bound to a specific IP address to receive broadcast packets. You can get around this by binding using INADDR_ANY, however in this case you may receive extra traffic you do not wish to receive (e.g. there are two Ethernet interfaces on the board). RTCS emulates BSD and we consider this to be an appropriate behavior. Q:If there is no file system on an MQX target running RTCS how can I use FTP to upload and download files to it? Say I have a datafile on a PC that I want to be able to upload over ethernet to my MQX app as well as later download it. Can I do that without a file system ... say get a file line by line and interpret it? Likewise output it line by line? A: Yes, this is possible, but it requires that you do some work to design the "device" to handle this. Without a file system, the FTP server can communicate with any MQX device - these are usually identified by a string such as "ttya:", "ittyb:", "flash:", etc. They can either by installed by the application or the BSP. The ones previously mentioned are installed by the BSP, but the RTCS apps example (apps.c) also installs two new devices called null: and kmem: In order to communicate with these devices via FTP, on the PC you would do the following: Type: ftp my_ip_address (prompt for user name) - hit Enter To put a file to the server, type: put localfilename remotedevice For example: put test.txt ttya: This will send the contents of test.txt from the PC to the target - the ttya: device will put it to the screen. If you replace ttya: with null: in the apps example, it will simply discard everything it reads. To get a file from the server, type: get remotedevice localfilename For example: get kmem: coredump This will store the contents of kernel data into a file on the PC Now, you can design your own device to do something similar. I would recommend looking at the source\io\io_mem and source\io\io_null devices to use as templates. Basically, you need to code an install, open, close, read, write and ioctl function for your device. When the FTP server calls fopen(), read() and write() on your device, it will access these functions. It would be up to you to decide what to do with the data once it arrives in your functions, but you could process it and also store it for later use. Note that both the RTCS TFTP and FTP *servers* use the same structure. The FTP client uses device names to access the data to send. However, the TFTP client API decodes the data without using a device. Q: Is there a documented API for the IP layer? A:This interface isn't documented since it's assumed that the user won't usually access it. There are four functions: IP_init(), IP_send() (for outgoing packets), IP_send_if() and IP_service() (for incoming packets). IP_send_if() is used only by BOOTP/DHCP to send a limited broadcast with a source IP address of 0.0.0.0. Q: How is the timer used on MQX? A: On ColdFires, timer PIT is used as system timer for scheduler (dispatcher) and for time counting. Q: How to free memory after use mem_alloc? A: Use mem_free
View full article
Sharing notes taken during creation of MQX 4.0 K10 BSP. These particular notes are for 72 MHz version of K10 (part number K10DX128VLL7), so the baseline BSP for this is twrk20d72m, tested with CodeWarrior IDE. (I believe analogous steps could be taken for other K10 versions as well, just need to select appropriate baseline BSP.) For the K10 BSP, we need to remove USB related code (as there is no USB module on K10) and add #elif into some *mk20.c files such as adc_mk20.c and spi_mk20.c.      1. Add a new unique CPU ID into c:\Freescale\Freescale_MQX_4_0\mqx\source\psp\cortex_m\psp_cpudef.h. For example: #define PSP_CPU_MK10DX128       (PSP_CPU_NUM(PSP_CPU_ARCH_ARM_CORTEX_M4, PSP_CPU_GROUP_KINETIS_K1X, 4))      2. Copy processor header file MK10D7.h from c:\Freescale\CW MCU v10.3\MCU\ProcessorExpert\lib\Kinetis\iofiles\MK10D7.h to c:\Freescale\Freescale_MQX_4_0\mqx\source\psp\cortex_m\cpu\mk10d7.h      3. In the header file: c:\Freescale\Freescale_MQX_4_0\mqx\source\psp\cortex_m\kinetis.h add #include "MK10D7.h" for your processor. For example: #elif   (MQX_CPU == PSP_CPU_MK10DX128)    #include "MK10D7.h"      4. Use BSP clone tool to clone baseline BSP (twrk20d72m) into a new BSP with a new name such as "board_k10d72m".      5. In user_config.h of the new BSP, c:\Freescale\Freescale_MQX_4_0\config\board_k10d72m\user_config.h change MQX_CPU as it follows: #define MQX_CPU                 PSP_CPU_MK10DX128      6. PSP builds OK. From BSP, we need to remove USB related code in init_gpio.c comment lines 609 and 612 c:\Freescale\Freescale_MQX_4_0\mqx\source\bsp\board_k10d72m\init_gpio.c: /* SIM_SOPT2_REG(SIM_BASE_PTR) |= SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK;*/ /* SIM_SCGC4_REG(SIM_BASE_PTR) |= SIM_SCGC4_USBOTG_MASK;*/      7. In CW IDE, remove USB source code from "bsp_board_k10d72m" build project under "Peripheral IO Drivers". Remove complete "usb" virtual folder from the BSP build project. Remove "init_usb.c" from "board_k10d72m BSP Files"      8. In BSP source file "spi_mk20.c" c:\Freescale\Freescale_MQX_4_0\mqx\source\io\spi\spi_mk20.c add #elif for k10: #elif (MQX_CPU == PSP_CPU_MK10DX128) static const pointer dspi_address[] = {    (pointer)SPI0_BASE_PTR,    (pointer)SPI1_BASE_PTR, }; static const uint_32 /*PSP_INTERRUPT_TABLE_INDEX*/ dspi_vectors[][1] = {    { INT_SPI0 },    { INT_SPI1 }, }      9. Similar change need to adc_mk20.c c:\Freescale\Freescale_MQX_4_0\mqx\source\io\adc\kadc\adc_mk20.c: #elif (MQX_CPU == PSP_CPU_MK10DX128) static const pointer adc_address[] = {    (pointer)ADC0_BASE_PTR,    (pointer)ADC1_BASE_PTR };      10. BSP project builds OK.      11. MFS, RTCS, SHELL projects build OK.      12. If you wish to build an MQX application with this new BSP, don't forget to change the paths to MQX libs and include files in your application project: C compiler "-i" option:   (for Debug build configuration)     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\bsp     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\psp     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\mfs     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\rtcs     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\shell     $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\bsp\Generated_Code Linker additional libraries:   psp.a, bsp.a, mfs.a, rtcs.a, shell.a Linker Library search paths:   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\bsp   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\psp   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\mfs   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\rtcs   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\shell Path to linker command file:   $(MQX_ROOT_DIR)\lib\board_k10d72m.cw10\debug\bsp\intflash.lcf
View full article
If anybody meets an issue with MQX 3.8 (also 3.8.1, 4.0 and 4.0.1) writing to a Compact flash (/mfs/examples/cfcard), there is an error in the cfcard io driver. Compact flash can be read, but writing doesn't work. Fix for this is in the source file: c:\Freescale\Freescale MQX 3.8\mqx\source\io\pcflash\apcflash.c in function _io_apcflash_write() on line 452, change from: results = _io_apcflash_read_write_blocks(fd_ptr, info_ptr, data_ptr, num, FALSE); change to: results = _io_apcflash_read_write_blocks(fd_ptr, info_ptr, data_ptr, num, TRUE); Tested on M5329EVB and MQX 3.8.1.
View full article
INTRODUCTION Have you posted a question and it has been unanswered? It could be because of couple of reasons. I would like to highlight few of them. Because posts like "it does not work" have a real chance to be ignored. More you share, easier for others to reproduce it. USE SEARCH FUNCTIONALITY Before you even start creating your own post, use search functionality here in the community. Lot of questions have been answered already, do not please duplicate posts. DOCUMENTATION Available documentation is located inside MQX installation folder: <MQX_INSTALL_DIR>\doc. There are two most important documents: MQX User Guide and MQX Reference Manual. You might find your answer there. HOW WOULD AN IDEAL POST LOOK LIKE It should contain: 1. product version (MQX version) 2. platform (MCU) 3. compiler (IDE) 4. target (release/debug and flash/ram) 5. detailed description 6. code snippet (if not the exact code, at least literally what it does and where it fails) The best is to post a code or at least a snippet of what fails. Try to minimize the software, create a small application which you can share to prove it is not functional properly. The code most of the time help us to reproduce a problem and make it fail in the same way. Otherwise we can only guess what it could be which makes entire process harder and longer. Please use C++ highlight (available in Advanced editor, last symbol (>>) ). It makes code easier to read with visual splitting a code from a text. /* code example (C++ higlight) */ int main(void) {   return 1; } If you tackle with any problem, please specify what you have done so far, read or tried anyhow. State what you expected to happen. Write down an error which has occur, if any. Does current version of MQX break the code which has been running on previous release? Diff files to find out differences. Does documentation not provide enough details? Does the code look obfuscated? Let us know! SHARING IS CARING We would like to hear your feedback! Share a result with us. Helps us to improve user experience! If you get an answer which has helped you, please reply and share the outcome, how did you solve it. Any user can encounter similar or even the same problem. Be part of the community. Regards, c0170 I'll post here some references which are valuable to the topic and I suggest everybody read them. References: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html http://www.softwaretestinghelp.com/how-to-write-good-bug-report/
View full article
TWR-K70F120M running MQX and RTCS can work with the Dual Phy on TWR-SER2. Below I list the modifications I did to the default BSP: 1) I add phy_dp83xxx.c and phy_dp83xxx.h to the bsp_twrk70f120m build project. These files are with MQX in /mqx/source/io/enet/Phy 2) I modify the BSP to use DP83xxx PHY for the Ethernet MACNET: in the /mqx/source/bsp/twrk70f120m/init_enet.c: #include "phy_dp83xxx.h" const ENET_IF_STRUCT ENET_0 = {      &MACNET_IF,      //&phy_ksz8041_IF,      &phy_dp83xxx_IF,      MACNET_DEVICE_0,      MACNET_DEVICE_0,      BSP_ENET0_PHY_ADDR,      BSP_ENET0_PHY_MII_SPEED }; 3) MDIO line requires an external pull up resistor, per DP83849I Data sheet. As I didn't have one at the moment, I enable internal pull up on MCU pin PTB0. in the /mqx/source/bsp/twrk70f120m/init_gpio.c: //pctl->PCR[0] = PORT_PCR_MUX(4) | PORT_PCR_ODE_MASK; /* PTB0, RMII0_MDIO/MII0_MDIO   */ /* PTB0, RMII0_MDIO/MII0_MDIO   */ /* internal pull up enabled on MDIO */ pctl->PCR[0] = PORT_PCR_MUX(4) | PORT_PCR_ODE_MASK | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; With these changes, the RTCS applications work over TWR-SER2 Dual PHY channel A. On TWR-SER2, J8 and J9 are un-shunted, SW1 = 11000000, SW2 = 10100000 on TWR-K70F120M, J18 is configured to disable 50 MHz OSC, as I use 50 MHz clock source from TWR-SER2 U504 50 MHz output. This clock is used to provide reference clock for the MCU (EXTAL), as well as for the Dual PHY X1 input (RMII reference clock).
View full article
Interrupts can be handled by MQX (MQX managed ISR) or bypassing MQX (MQX kernel ISR). If you want that MQX handled all the ISR process, you can use MQX managed ISR.  By this ISR,  MQX catches all hardware interrupts in the range that the BSP defined and saves the context of the active task. For most interrupts, MQX calls the ISR that is stored in the interrupt vector table at the location identified by its interrupt vector number. The disadvantage with this is the interrupt latency is longer and depends completely on MQX. Hardware vector table for all MQX managed isrs points to MQX kernel function _int_kernel_isr()). This function invokes user isr by jumping into instruction pointed by "isr_ptr" , as the below graph shows. A task can install an MQX managed ISR interrupt using:  _int_install_isr(interrupt_vector_number,isr_ptr,isr_data_ptr) _bsp_int_init(Vector, Pri, Subpri, TRUE); Vector – number of non-core vector (for example, 37 for LLWU, defined in IRQInterruptIndex in the MCU header file) Pri – priority of the interrupt source. Allowed values: MQX_HARDWARE_INTERRUPT_LEVEL_MAX, MQX_HARDWARE_INTERRUPT_LEVEL_MAX + 1, …, 7, where 7 is the lowest application interrupt priority level. Subpri – zero on Kinetis. Enable – TRUE to enable the interrupt vector source in NVIC.  At this level of interrupt, you can call MQX services. The other option is MQX kernel ISR. Some real-time applications need special event handling to occur outside the scope of MQX. The need might arise that the latency in servicing an interrupt be less than the MQX interrupt latency. If this is the case, an application can use _int_install_kernel_isr() to bypass MQX and let the interrupt be serviced immediately. You will have the very same Performance as if you were running bare metal. A kernel ISR must save the registers that it needs and must service the hardware interrupt. When the kernel ISR is finished; it must restore the registers and perform a return-from-interrupt instruction. Even though the compiler handles this for you.   In this case, you can't use MQX services.  However, you can put data in global area, which a task can access. The disadvantage on this is shared data problem and you can impact the kernel if the restoring stack fails.   If you need faster MQX kernel ISR, you can install Kernel ISR with : _int_install_kernel_isr(vector_num, isr_ptr)  _bsp_int_init(Vector, Pri, Subpri, TRUE); Vector – number of non-core vector (for example, 79 for FTM1, defined in IRQInterruptIndex in the MCU header file) Pri – priority of the interrupt source. Allowed values: 0 for highest priority kernel isr, 1, ..,MQX_HARDWARE_INTERRUPT_LEVEL_MAX-1 for lowest priority kernel isr. Subpri – zero on Kinetis. Enable – TRUE to enable the interrupt vector source in NVIC. And very important, to install a HW interrupt handler, you need the HW interrupt table in RAM, so your user_config.h has to define MQX_ROM_VECTORS to 0.   Next is a demo to show how to use mqx kernel ISR, you can download it for more details.   static void GPIO_Init(void); static void IRQ_Init (void); void PortA_ISR(void); void PortE_ISR(void);                TASK_TEMPLATE_STRUCT MQX_template_list[] = { /*  Task number, Entry point, Stack, Pri, String, Auto? */    {MAIN_TASK,   Main_task,   1500,  9,   "main", MQX_AUTO_START_TASK},    {0,           0,           0,     0,   0,      0,                 } };   char SW=0;     /*TASK*----------------------------------------------------- * * Task Name    : Main_task * Comments     : *    This task prints " Hello World " * *END*-----------------------------------------------------*/   void Main_task(uint_32 initial_data) {    int counter=0;                printf("\n Hello World \n");       GPIO_Init();       IRQ_Init();       while(1){                   if(SW==1){                                  SW=0;                                  printf("IRQ A was generated\n");                   }                   if(SW==2){                                  SW=0;                                  printf("IRQ E was generated\n\r");                   }                   printf("Waiting for IRQ... %d\n\r", counter);                   counter++;                   _time_delay(1000);    }       _mqx_exit(0); }   static void GPIO_Init(void){                               SIM_SCGC5 = (0|SIM_SCGC5_PORTA_MASK|SIM_SCGC5_PORTE_MASK); /* Enable clock for PORTA */                               PORTA_PCR19 |= (0|PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA));//|PORT_PCR_PE_MASK;//|PORT_PCR_PS_MASK;                PORTE_PCR26 |= (0|PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA))|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK; }   static void IRQ_Init (void){                uint32_t result;                                                  /* install the interrupt routine */                _int_install_kernel_isr (103, PortA_ISR);                _int_install_kernel_isr (107, PortE_ISR);                                              result = _cortex_int_init(107, 2, TRUE);                result = _cortex_int_init(103, 3, TRUE);                }   void PortA_ISR(void){                SW=1;                PORTA_ISFR=0xFFFFFFFF;  //Clear Port A ISR flags }   void PortE_ISR(void){                SW=2;                PORTE_ISFR=0xFFFFFFFF;  //Clear Port E ISR flags }
View full article
MQX RTOS Task Aware Debugging plug-in (TAD) is an optional extension to a debugger tool which enables easy debugging of multi-tasking applications. With TAD, we can inspect task contexts and kernel objects. Typical use cases include --view task error codes --Examine stack usage for each task --Examine memory usage -- Debug TCP reception problems --Examine socket and PCB data --Observe memory pool / message pool utilization levels -- Observe synchronization objects The following is a description of MQX task aware debugger and an example to debug a stack overflow. It is based on web_hvac demo in the MQX installation folder, it also applies to other applications. The MQX pull down menu is as below picture shows. The task summary window shows all the tasks in the system, the task name , task id , task state, priority and Task error code. The idle task is also listed since this is still treated by MQX  as a task, and can be helpful to know what’s happening with it. The stack usage window shows what percentage that allocated for a task interrupt have been used so far. This is a high watermark not the amount of the stack currently been used. If more than allocated stack is being used as some point, then you will see an over flow has been indicated at last column. Also for reference, the address for both the base for up and down are  shown. The kernel data window can be useful for confirming the environment you are running is actually what was loaded. You give them some key data such as the version of MQX running, the CPU, the PSP.  The settings of the time component and a number of the compile time configuration settings to confirm if you have things like the kernel logging or stack monitor turned on. The memory blocks window shows all of the blocks of memory that memory manager has currently reserved for kernel objects or application tasks.  Listed is starting address for each block , the size of each block in hexadecimal , who is the owner of each block.  Which can be either the system or specific tasks, and shows the type of block. We see different types such as the block for interrupts stack, system stack, task ready queue, block associated with interrupts.  The logging feature, message pools etc. Down to the bottom, we see the stacks specific memory blocks including the task descriptor and task space.  TAD knows what the task descriptor is so it gives all the information related to the task. The next group of windows  are related to various synchronizations  that MQX supports.  Such as semaphores and events ,mutexes. If some are greyed out and that because application doesn’t use it.  Example of Debugging with TAD In order to gain experience using the Task Aware Debugging (TAD) feature and to learn how it can be used to debug an application, I created a stack overflow in the shell task in web_hvac demo by reducing the task stack size from 2400 to 500. If I now run the application, we can see the application run into idle task quickly. Opening up the stack usage window, we see that indeed an overflow was detected. And that the stack information for the Shell task has been corrupted as a result.  The task summary window also has the corrupted information for the shell task. If you look closely, the listed tasks are short than before, and if you compare the list of tasks what you expected to be there. You noticed to shell task has completed disappear. But when we look at the console, we see that it clearly started. So where did it go? The stack overrun is a good clue. But also recommend scanning check for errors window. By reviewing the task summary, stack usage and errors windows, and doing a sanity check again the states values that expecting   can be very helpful ,make sure all the tasks are there. Check for error codes, and look for stack issues. To debug an application, the following steps should be follow: Review key TAD windows:                  Task Summary Window Stack Usage Window MQX Errors Window Audit various system parameters: -     Which tasks are running. -     Task states -     Check for identified errors -     Look for stack overflows
View full article
Several reasons may lead to a hard fault, for example, calling a function pointer with an invalid address, stack overflow, trying to read or write to an on-chip peripheral that is powered down or not being clocked, accessing non-mapped memory etc. It is often difficult to find out what caused the hard fault, fortunately the cortex-M stores some information in ARM fault status register, the hardware automatically pushes several CPU register on the stack before entering the Hard Fault Handler. This document below shows a way to debug a Hard Fault in MQX. For Hard Fault, we can hook our exception handler into the vector table. we will find vector table in the vector.c source file in the BSP library. By default, isr is configured to DEFAULT_VECTOR, which is the _int_kernel_isr() function of the MQX dispatcher. We cam put our own function, like void my_kernel_isr (void), to vector table offset 0x0c.  Inside my_kernel_isr(), we can get the interrupt stack frame, CPU register content at the time of exception and use directly the my_kernel_isr - just remove the static keyword, as we need the my_kernel_isr to be global, as it is referenced from vectors.c and it will be implemented in the application, main.c, for example.  Now, put breakpoint to this my_kernel_isr and see the registers read by prvGetRegistersFromStack(). Typically at most interest would by "lr" and "pc". For example, "lr" would have an address of an instruction that a return from a function call would return to. By looking into the .map file or using the debugger, we will know, which function has been executed by the CPU when exception occurred. Hook our own kernel isr into the vector table In file vectors.c,   the default ISR for Hard_Fault is DEFAULT_VECTOR Now we modified it to my_kernel_isr, so when hard fault happens, my_kernel_isr will be executed. Read the register value The following code is for CodeWarrior/Kinetis Design Studio to a C module, for IAR/KEIL, we need to write the same function as an assembler source file. void my_kernel_isr( void ) __attribute__( ( naked ) ); /* The fault handler implementation calls a function called prvGetRegistersFromStack(). */ static void my_kernel_isr(void) {     __asm volatile     (         " tst lr, #4                                                \n"         " ite eq                                                    \n"         " mrseq r0, msp                                             \n"         " mrsne r0, psp                                             \n"         " ldr r1, [r0, #24]                                         \n"         " ldr r2, handler2_address_const                            \n"         " bx r2                                                     \n"         " handler2_address_const: .word prvGetRegistersFromStack    \n"     ); } void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress ) { /* These are volatile to try and prevent the compiler/linker optimising them away as the variables never actually get used.  If the debugger won't show the values of the variables, make them global my moving their declaration outside of this function. */ volatile uint32_t r0; volatile uint32_t r1; volatile uint32_t r2; volatile uint32_t r3; volatile uint32_t r12; volatile uint32_t lr; /* Link register. */ volatile uint32_t pc; /* Program counter. */ volatile uint32_t psr;/* Program status register. */     r0 = pulFaultStackAddress[ 0 ];     r1 = pulFaultStackAddress[ 1 ];     r2 = pulFaultStackAddress[ 2 ];     r3 = pulFaultStackAddress[ 3 ];     r12 = pulFaultStackAddress[ 4 ];     lr = pulFaultStackAddress[ 5 ];     pc = pulFaultStackAddress[ 6 ];     psr = pulFaultStackAddress[ 7 ];     /* When the following line is hit, the variables contain the register values. */     for( ;; ); } Notes about Cortex M4 registers: MQX sets active stack pointer to PSP in boot.s The core automatically switches the active stack pointer to MSP in handler mode and switches back to PSP with exception return Compare with .map file we need to find out which function executes while hard fault occurs. To determine application , Use trace debugging tool (DSTREAM, ULINK-PRO, J-Trace, Lauterbach uTrace for Cortex-M …) or enable Kernel log and explore its content with MQX TAD #define MQX_KERNEL_LOGGING 1   _klog_create(2048,LOG_OVERWRITE);   /* Enable kernel log */   _klog_control(KLOG_ENABLED | KLOG_CONTEXT_ENABLED |                 KLOG_INTERRUPTS_ENABLED| KLOG_FUNCTIONS_ENABLED | KLOG_INTERRUPT_FUNCTIONS |                 KLOG_MEMORY_FUNCTIONS | KLOG_PARTITION_FUNCTIONS, TRUE); By this we only find, which function causes the problem. Next, we will have to think why this occurs, and give more application specific debugging effort to find the root cause.
View full article
In this section, we will cover the light weight ADC driver, which enable you to read the ADC the output and raw form, and converted to scale form , or even as average level over a number of reads. The light weight ADC driver also allows you to configure a number of attributes of the converter.  So you can customize your application. Quick overview of ADC ADC is a system that converts an analog signal into digital signal. Simply put, Analog signals here means any variable voltage that is being monitored. It doesn’t matter what the signal is doing, it can remain the same level continuously, it can have slight wave to it, or it can be seemingly random. The analog to digital converter requires you to provide the reference voltage. That defines the maximum level that the input can be.  To determine the voltage level of the input the circular ADC generate a local voltage, and just this level until the same level as the input.   This can be done in different ways but the circuitry will adjust the level of the local signal until the comparator to detect the two inputs are the same or lease the same as the resolution of ADC, once the signal level is matched, the output generated.  Which can be read by your application.  To calculate the signal level the ADC defines the full range from the input into the three levels.  ADC typically have a resolution of 12 to 16 bits, so the 2 12   to 2 16 different levels. Whatever level input signals determined to be add , the reading from the ADC will be a digital representation of this value compare the  reference voltage. The digital output then represents what percentage of the allowed input range the input signal is currently add. Being at the minimum level will result an output of zero and being the max will resut in an output of 0xffff. And for inputs some in between the result is the output that represents the level measured. So if you are using a reference voltage of 3.3V for example, the reading will represent what flection the 3.3 v  the input voltage is .  If the input voltage is zero.  The reading will be 0 of course. And if the input is 3.3 v, the reading will be all FF, meaning 100 percent. So in between, if the input voltage is 1v, the result will be roughly 30.3%. And an input of 2v, will result the input roughly 60.6%, and 3v will be 90.9%. ADC Driver in MQX architecture Diagram The light weight ADC driver is considered a low level driver and is located alongside the LWGPIO driver. This is because we don’t trade the interfaces as a part of serial communication, they passing data back and forth in blocks or in bytes, also it doesn’t make sense to be accessing the drivers through the IO subsystem.   There is a section dedicated to ADC module in bsp files folder in project. (take twrk70f120m for example) The ADC priority is defined as 3, though ADC is typically not used with interrupts,  The default reference voltage and maximum voltage is 3300mV. The input setting of the potentiometer is connected to ADC1_SOURCE_AD20 in Twr-k70 board. The adc1 device is designated as the default ADC device ADC API    1 _lwadc_init() This function initializes the ADC module according to the parameters given in the platform specific initialization structure. Call to this function does not start any ADC conversion. This function is normally called in the BSP initialization code.   2  _lwadc_init_input () This function initializes the application allocated LWADC_STRUCT with all data needed later for quick control of particular input. This function sets the ADC input to continuous conversion mode if not already in this mode. 3 _lwadc_set_attribute / _lwadc_get_attribute :  both this functions receive a pointer to the LWADC_STRUCT_PRT ,  and the attributes you interested in. All the attributes are defined in an enum LWADC_ATTRIBUTE. 4 _lwadc_read_raw () Read the current value of the ADC input and return the result without applying any scaling. 5 _lwadc_read () This function reads the current value of the ADC input, applies scaling according to preset parameters. 6 _lwadc_read_average() This function reads num_sample samples from the specified input and returns the scaled average reading. 7  _lwadc_wait_next() This function waits for a new value to be available on the specified ADC input.
View full article
Hello All,   I want to share a client-server project. In this example the server can accept more than one client (Daemon server implementation). This example was created and tested using MQX4.2, CodeWarrior 10.6 and FRDM-K64F boards.     In general, the client-server model is the most common communication model used by the applications such as HTTP, Telnet, FTP, SSH, and others. In a client-server model, the server listens to client requests and waits for new connections. When a client needs to connect to a server, it sends a request. The server acknowledges the request, and if the client is supported by the server, the connection is established.   A TCP client-server communication can be implemented as in the following figure.         SETTING THE RTCS Below are presented the steps required to set the RTCS with the default settings: Create the RTCS. This step reserves memory for different RTCS parameters and initializes the TCP/IP task. Each project (server and client) contains an RTCS.c file which contains the initialize networking function with the RTCS configuration.     Set the RTCS IP address to the device after initialization. The main.h files have the macros and variables that store the IP parameters. You can change the IP address according your needs. In RTCS.c files,  the following code sets the address, mask, gateway and server IP addresses. ip_addr = IPADDR(A,B,C,D); phy_addr = BSP_DEFAULT_ENET_DEVICE; . . . ip_data.ip = ip_addr; ip_data.mask = ENET_IPMASK; ip_data.gateway = 0;     Calculate the MAC address for the device using the variables. Use the ENET_get_mac_address() function to build a valid MAC address for the application. MAC address calculation takes the device number and IP address as parameters, and returns a valid MAC address in the IPCFG_default_enet_address variable.   Initialize the Ethernet device available in the board with the calculated MAC address. Use the ipcfg_init_device() function to tell the RTCS task what Ethernet device should be used and to set the calculated MAC address to that device. Once the MAC address is set and the device is initialized, it is possible to bind the device to the IP address. error = ipcfg_init_device (phy_addr, serverAddress);     After Ethernet device initialization, bind the device to the IP address and it is ready to communicate. /* If DHCP Enabled, get IP address from DHCP server */              if (dhcp) {                     printf("\nDHCP bind ... ");                     error = ipcfg_bind_dhcp_wait(phy_addr, 1, &ip_data);                     if (error != IPCFG_ERROR_OK) {                            printf("Error %08x!\n", error);                     }                     else {                            printf("Successful!\n");                     }              } else {        /* Else bind with static IP */                     printf ("\nStatic IP bind ... ");                     error = ipcfg_bind_staticip(phy_addr, &ip_data);                       if (error != IPCFG_ERROR_OK) {                            printf("Error %08x!\n",error);                     }                     else {                            printf("Successful!\n");                     }              }     SERVER IMPLEMENTATION              For the server implementation, MQX uses a socket structure that is created and filled in this way: laddr.sin_family      = AF_INET; laddr.sin_port        = CONNECT_PORT; laddr.sin_addr.s_addr = INADDR_ANY;   The socket() function creates an unbound socket in a communications domain. This function also returns a handler used in later function calls that operate on sockets. /* Listen on TCP port */ listensock = socket(PF_INET, SOCK_STREAM, 0); if (listensock == RTCS_SOCKET_ERROR) { error = RTCSERR_OUT_OF_SOCKETS; }   The bind() function assigns a local socket address to a socket and the listen() function marks a socket as accepting connections. error = bind(listensock, &laddr, sizeof(laddr)); if (!error) {        error = listen(listensock, 0); }   The accept() function extracts the first connection on the queue of pending connections, creates a new socket with the same socket type protocol and address family as the specified socket, and allocates a new file descriptor for that socket. child_sock = accept(listensock, NULL, NULL);   The recv() function receives a message from a socket. error = recv(sock, (void *)cRecvBuff, sizeof(cRecvBuff), MSG_WAITALL);                     The send() function initiates transmission of a message from the specified socket to its peer. The send() function sends a message only when the socket is connected. error= send(sock, (void *)cRecvBuff, sizeof(cRecvBuff), 0);     The messages received are checked in order to toggle a LED or shutdown the connection. while(1)        {              error = recv(sock, (void *)cRecvBuff, sizeof(cRecvBuff), MSG_WAITALL);              printf("Received: %s\n", cRecvBuff);              if (error == RTCS_ERROR)              {                     printf("There was an error code %lx\n", RTCS_geterror(sock));                     shutdown(sock, FLAG_CLOSE_TX);                     return;              }              if(cRecvBuff[0]=='T')              {                     printf("Received: %s\n", cRecvBuff);                     printf("LED was toggled from child\r\n");                     lwgpio_toggle_value(&led1);              }              if(cRecvBuff[0]=='G')              {                                              printf("Received: %s\n", cRecvBuff);                     printf("Shutting down connection\n");                     shutdown(sock,FLAG_CLOSE_TX);                     _time_delay(2000);                      _task_abort(MQX_NULL_TASK_ID);              }            }            CLIENT IMPLEMENTATION   For the client implementation, it uses a socket structure that is created and filled in this way: addr.sin_family      = AF_INET; addr.sin_port        = DESTPORT; addr.sin_addr.s_addr = IPADDR(192,168,1,200); //Server address   The socket() function creates an unbound socket. sock = socket(PF_INET, SOCK_STREAM, 0);     The connect() function attempts to make a connection on a socket. error = connect(sock, &addr, sizeof(addr));        The recv() function receives a message from a socket. error= recv(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);          The send() function sends a message only when the socket is connected (including when the peer of a connectionless socket has been set via connect() function). error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);          In addition the client example can toggle a LED in the server board or destroy the socket. /*****Infinite loop waiting for user to push a button***/ while(1){        if(lwgpio_get_value(&btn1) == LWGPIO_VALUE_LOW)        {              _time_delay(150);              sprintf((char *)cReadBuff, "Toggle from client2\n");              printf("Sending: %s", cReadBuff);              error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);              if (error == RTCS_ERROR)              {                     printf("There was an error trying to send to the server\n");                     return;              }        }        if(lwgpio_get_value(&btn2) == LWGPIO_VALUE_LOW)        {              _time_delay(150);              sprintf((char *)cReadBuff, "GoodBye\n");              printf("Sending: %s", cReadBuff);              error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);              if (error == RTCS_ERROR)              {                     printf("There was an error trying to send to the server\n");                     return;              }              printf("Shutting down connection\n");              shutdown(sock,FLAG_CLOSE_TX);              _task_abort(MQX_NULL_TASK_ID);        }       I hope this helps, Soledad Original Attachment has been moved to: ClientD_FRDM-K64_MQX4_2_CW10_6.zip Original Attachment has been moved to: ServerDeamon_FRDM-K64_MQX4_2_CW10_6.zip
View full article
SPI, which stands for Serial Peripheral Interface, is a standard with a very specific hardware interface. A connection is between a master and a slave, with the master typical being a processor, and the slave being a peripheral such as a sensor, flash memory device, or a modem chip.   It can also be used for processor to processor communications, but in this case, an additional handshake signal is often used. There are normally four signals between a master and a slave, the first is a clock signal, and this signal is always driven by the master, regard which device is transmitting.  The second line is a data line for data going from the master to the slave, and this is designated as the master output, slave input line, are MOSI for short. It connects the SPI data out connection on the master and to the SPI data in connection on the slave. The next conductor is for data in the opposite direction and is labelled as the master input slave output line, are MISO for short. The last conductor is slave select with the slave chip selecting input, and is active low. If you have more than one slave, with the first being perhaps a sensor of some kind, the slave will be dedicated to slave 1. If you add a second sensor, the top 3 interface line will be shared, but it dedicates for slave’s line will be required for the second device, and the same is true of course for each of additional slave device. Most processors have a maxim of 4 slave selected lines.  The four lines could be used effectively as a multiplexed address lines to access more than 4 slaves. You cannot have more than one master on the bus,   since the interface is not support coordination between two masters as to which one is controlling the bus. Transmissions are typically sent as a sequence of bytes, but without a formal protocol, there is nothing restricting communication being   byte based. Typical by frame sizes, are in 8 to 32 bits range.  Also note the bytes and packets are not acknowledged as they are in i2c, and you could have a master synching communicating with the slave but, you don’t really know of your communications are being received OK. However, some slave devices will echo bytes sent to it, which provides an acknowledgement to the master.  it is how the data lines are synchronized with a clock signal. Clock Polarity and Phasing There are four different modes available, one mode each combination clocking in a low state and high state, with a data being read in a rising edge or falling edge of the clock signal.  For modes 0 and 1, the clock is low in idle, which is referred to  as clock and 0,  For modes 2 and 3 then the clock is in high state when idle, so it has  polarity  , one , For modes 0 and 2, the data will be sampled by the receiving device  on the leading edge of a clock signal.  Relative to the idle state, which is referred to a clock phase of zero. So for mode 0, this means the rising edge of the clock and for mode 2, means the following edge of the clock, the other two modes, use a clock phase 1 which means that trailing edge of clock as a returns to an  idle state.  And this translates to a following edge for mode 1 and the rising edge for mode 3.  Mode 0 is the most commonly supported setting. If multiple slaves in the same bus, you may have to reconfigure the settings for the master to which modes when you want to communicate with a different slave.
View full article
The Kinetis Software Development Kit (KSDK) is a software framework for developing applications on Kinetis MCUs. The software components in the framework include peripheral drivers, middleware and real time operating systems. KSDK provides FreeRTOS OS, selected drivers provide FreeRTOS support in form of an additional layer. This solution enables simple driver integration in RTOS-based applications. Drivers with FreeRTOS layers are: • UART / LPUART / LPSCI • I2C / LPI2C • SPI / LPSPI The drivers for FreeRTOS OS is a layer built on top of standard KSDK peripheral drivers to achieve multithread (RTOS) awareness. The wrappers provide an API which blocks the calling task until the I/O operation completes and allows other tasks to run in the background. This is achieved by using the asynchronous API of the underlying driver along with RTOS task synchronization objects. Underlying drivers require enabled interrupts for proper operation. In addition, it is possible to use the KSDK bare metal drivers. This document shows how to use the LPTMR Driver in a FreeRTOS and SDK 2.0 project. For this example it is used SDK 2.0, FRDMK64F and FreeRTOS. If you want to know how to create a new SDK 2.0 with FreeRTOS project please check the below link: https://community.freescale.com/docs/DOC-330183 GPIO AND LPTMR EXAMPLE: Introduction This example toggle the Blue LED every 1 second. This example check the Timer Compare Flag bit, when this flag is set blue LED changes status. Writing the example code First it is necessary to create a new SDK 2.0 with FreeRTOS project, please check the below link for do that.      https://community.freescale.com/docs/DOC-330183    2. After create a new project, open the pin_mux.c file in order to enable the port clock and configure the necessary pins as GPIO (for FRDM-K64F the RGB LED is connected   through GPIO signals: RED to PTB22, BLUE to PTB21 and GREEN to PTE26).   3. In addition, it is necessary to enable the clock for the lptmr module, in the pin_mux.c file.   4. In main.c file it is necessary to include the fsl_lptmr.h and fsl_gpio.h.   5. In main function, create a new task. This task will initialize the LPTMR and GPIO drivers. For this example the new task function was named task_init. /* Create RTOS task */    xTaskCreate(                  task_init,                  "Task_Init",                  configMINIMAL_STACK_SIZE,                  NULL,                  task_PRIORITY,                  NULL);     6. Write the task_init function code.                   a. Using the KSDK GPIO driver: To initialize the GPIO, define a pin configuration, either input or output, in the user file. Then, call the GPIO_PinInit() function. In this case the pin PTB21 where blue LED is connected was configured as output. gpio_pin_config_t ledB_config = {kGPIO_DigitalOutput, 0,}; GPIO_PinInit(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN, &ledB_config); After configure the GPIO pins, it is possible to use the below GPIO operations: GPIO OUTPUT OPERATIONS. GPIO_WritePinOutput  (GPIO_Type *base, uint32_t pin, uint8_t output) GPIO_SetPinsOutput (GPIO_Type *base, uint32_t mask) GPIO_ClearPinsOutput (GPIO_Type *base, uint32_t mask) GPIO_TogglePinsOutput (GPIO_Type *base, uint32_t mask) GPIO INPUT OPERATIONS. GPIO_ReadPinInput (GPIO_Type *base, uint32_t pin) The board.h file contains definitions for this operations. For example: /*!< Toggle on target LED_BLUE */ #define LED_BLUE_TOGGLE() \ GPIO_TogglePinsOutput(BOARD_LED_BLUE_GPIO, 1U << BOARD_LED_BLUE_GPIO_PIN)                   b. Using the KSDK LPTMR driver: The LPTMR_Init () should be called at the beginning of the application using the LPTMR driver. This function initializes the lptmr_config_t structure, this structure holds the configuration settings for the LPTMR peripheral. To initialize this structure to reasonable defaults, call the LPTMR_GetDefaultConfig () function and pass a pointer to your config structure instance. The config struct can be made const so it resides in flash. The default values are: config->timerMode = kLPTMR_TimerModeTimeCounter; config->pinSelect = kLPTMR_PinSelectInput_0; config->pinPolarity = kLPTMR_PinPolarityActiveHigh; config->enableFreeRunning = false; config->bypassPrescaler = true; config->prescalerClockSource = kLPTMR_PrescalerClock_1; config->value = kLPTMR_Prescale_Glitch_0; After configure the LPTMR, it is necessary to set the timer period. The LPTMR_SetTimerPeriod(), the timer counts from 0 till it equals the count value set here. The count value is written to the CMR register. Finally start the timer using the LPTMR_StarTimer (). After calling this function, the timer counts up to the CMR register value. Each time the timer reaches CMR value and then increments, it generates a trigger pulse and sets the timeout interrupt flag. An interrupt will also be triggered if the timer interrupt is enabled. For this example the below lines configure and start the LPTMR. /* Configure LPTMR */ LPTMR_GetDefaultConfig(&lptmrConfig); /* Initialize the LPTMR */ LPTMR_Init(LPTMR0, &lptmrConfig); /* Set timer period */ LPTMR_SetTimerPeriod(LPTMR0, USEC_TO_COUNT(1000000U, LPTMR_SOURCE_CLOCK)); /* Start counting */ LPTMR_StartTimer(LPTMR0);                   c. This example check the Timer Compare Flag bit, when this flag is set blue LED changes status. So in an infinity loop the LPTMR_GetStatusFlags() function check                       the status flag, if this flag is set then toggle the LED and clear the flag using the the LPTMR_ClearStatusFlags() function. while (1)    {    if (LPTMR_GetStatusFlags(LPTMR0) )           { LED_BLUE_TOGGLE();                       LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);                } }   7. At this point you can build and debug the example. Complete Code GPIO and LPTMR Example #include <string.h> #include "board.h" #include "pin_mux.h" #include "clock_config.h" #include "fsl_debug_console.h" #include "fsl_device_registers.h" #include "fsl_lptmr.h" #include "fsl_gpio.h" /* FreeRTOS kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "timers.h" /* Task priorities. */ #define task_PRIORITY (configMAX_PRIORITIES - 1) /******************************************************************************* * Definitions ******************************************************************************/ /* Get source clock for LPTMR driver */ #define LPTMR_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_LpoClk) static void task_init(void *pvParameters); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t lptmrCounter = 0U; int main(void) {        /* Init board hardware. */        BOARD_InitPins();        BOARD_BootClockRUN();        BOARD_InitDebugConsole();        /* Add your code here */        /* Create RTOS task */        xTaskCreate(                      task_init,                      "Task_Init",                      configMINIMAL_STACK_SIZE,                      NULL,                      task_PRIORITY,                      NULL);        vTaskStartScheduler();        for(;;) { /* Infinite loop to avoid leaving the main function */               __asm("NOP"); /* something to use as a breakpoint stop while looping */        } } static void task_init(void *pvParameters) {        for (;;) {               lptmr_config_t lptmrConfig;               PRINTF("You are running the initialization task.\r\n");               /* Init output LED GPIO. */               gpio_pin_config_t ledB_config = {kGPIO_DigitalOutput, 0,};               GPIO_PinInit(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN, &ledB_config);               PRINTF("LED BLUE initialized \r\n");               /* Configure LPTMR */               /*                * lptmrConfig.timerMode = kLPTMR_TimerModeTimeCounter;                * lptmrConfig.pinSelect = kLPTMR_PinSelectInput_0;                * lptmrConfig.pinPolarity = kLPTMR_PinPolarityActiveHigh;                * lptmrConfig.enableFreeRunning = false;                * lptmrConfig.bypassPrescaler = true;                * lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_1;                * lptmrConfig.value = kLPTMR_Prescale_Glitch_0;                */               LPTMR_GetDefaultConfig(&lptmrConfig);               /* Initialize the LPTMR */               LPTMR_Init(LPTMR0, &lptmrConfig);               /* Set timer period */               LPTMR_SetTimerPeriod(LPTMR0, USEC_TO_COUNT(1000000U, LPTMR_SOURCE_CLOCK));               PRINTF("Low Power Timer module initialized \r\n");               /* Start counting */               LPTMR_StartTimer(LPTMR0);               while (1)               {                      if (LPTMR_GetStatusFlags(LPTMR0) )                      {                            lptmrCounter++;                            LED_BLUE_TOGGLE();                            LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);                      }               }        } }
View full article
  I2C is a common way to interface a processor with a peripheral such as EEPROM, accelerometer, or communication device, and can even be used to communicating with another processor. Quick Review of I2C I2c: inter-integrated circuit, meaning that is a communication channel between integrated circuit devices, typically from a microprocessor to a peripheral device, such as a memory chip, some type of sensor, a data converter or maybe a display.   By design, i2c isn’t intended for high throughput connections, so you won’t see it used for something like chip ram, rather it is typically used when relatively small amount of data is being sent or received. There are only two conductors through the i2c bus, the first is a serial clock line which is usually written as SCL,   as the name implies, SCL is a clock signal sent on this line. The second is a serial of data line, or SDA, and the data sender on this line will be synchronized with a clock signal making it easier for the receiver to decoding incoming data, and i2c connections is one to one link, with one device being as a master and the other being a slave.  But multiple devices can be connected to the same bus with different one to one pairs communicating on the channel. Only one pair can be communicating at a time of course, and having more than one device capable of being a master will acquire additional synchronization to avoid conflicts. With i2c, the communication is poll response, meaning the master will poll slave with either data that wants to send to slave or send a command request the slave sends specific information back, only the master can initiate communication and part of the job is to provide the clock signal, which should does not only when is transmitting,    but also when the slave is transmitting back. Sending Data with I2C The clock and data lines have pull up resistors, so when the bus is idle and both of the wires will be in high state. To begin a transmission,  a master  pulls a data line low which is refer to as a start condition , the master then drives the clock signal while  sent 7 address bits on the data line.  The address bits are followed immediately by either a 0 to indicate the master wants to send the data or a 1 meaning the master would like to read the data back from the slave, the seven address bits must closely bound to a slave device that is on the bus of course, and the device with margin address will set as an acknowledge or an ACK bit on the data line to   indicate that has receive the request which is done by holding the data line low. At this stage, one of two things going to happen. If the master wants to send data or   a command to address the slave , he will continue on with first byte to transmit ,  data bits will sent out   and again the address slave or add the   ACK bit at the end , this continues until the master is done sending it’s commanding data. And there is no fixed limit to size of the message. If the master is just sending data and is not expecting receive response back from the slave, it will indicate that is done by signaling a STOP condition, after the last data byte is sent. However, instead of sending data,  the master maybe expecting the salve to immediately to reply back and signals this request, with a read bit have the address, In this case,  slave acknowledge address and then sent out a byte of data synchronize to  the master’s clock , once the byte is complete, the master will indicate acknowledgement of  the data, and this continues until the master receives the amount of data  it was expecting. It signals to the device the expected amount of data has been received by not acknowledging a last byte. And instead leaves the data line high, which is called the NAK for not acknowledge. Finally the master terminates the communication by signaling a stop condition and stops generation of the clock signal. And the last thing to cover is the case when the master like to send either data or a command and immediately receive data back from the slave. So a combination of previous two scenarios,   the first part of the transaction is identical to just sending data with master sending out the number of bytes has to transmit, and the slave acknowledge each byte. However, the stop condition is not asserted at the end of transmission, and the master will send a start bit , which is called a repeatedly start bit. The seven address bits will send again followed by a read setting which the slave acknowledge. The slave then send the data with the master’s address on each byte until the last byte which isn’t acknowledged, and the session is terminated with a stop bit. Note: This document is the 11th Installment of the "Essentials of MQX RTOS Application Development" training course. Please watch the vedio for more details MQX RTOS Part 11: IC2 Driver|NXP
View full article
Flash memory is critical component to any system, and it’s important to be able to access flash memory efficiently. In this document, we will look at the differences between the two main types of flash used today, NAND flash and NOR flash, how to erase and access flash. Then we will look at the MQX flashx driver, which can be used for both types of flash. Accessing NOR and NAND Flash There are two main types of flash memory, the first being nor flash , and the second being nand. For an interface point of view, the main difference is how the data is accessed. Nor flash is a full address and data  bus, similar to random devices, and nand devices is using io bus with commands , address and data being multiplexed to share the same bus. It is greatly reduces the number of pins to require connectivity in devices , But for software and data access perspective , there are more significant differences between the two types of memory. At the core, each bit is storing using different tech knowledge. With nor flash , the memory region is divided by equal size units called blocks.  The size of each block in today’s technology ranges from roughly 32k bytes to 128 kbytes, but this is  totally dependent on the devices select and over the years this is changed.  The internal circuitry of nor flash allows each byte of the device can be individually addressable in the same way that you can address bytes stored in ram, or in an EEPROM and this is why a full bus is used with nor flash. However this only applies for reading a byte or programming an individual byte, the racing skimming must be done at the block level,  so unlock a  race state requires the entire block to be affected. Nand flash , however, has being purposely architected differently in order to increase the storage density.  It too has a memory region divided in equal size of  blocks, but each of these blocks are further broken down into samll regions that are called pages, the page is typically 2k bytes in size and a block often has 64 pages, so 128 kbytes , to the lead data you still be working at the block level, but if you want to read and program part of flash, this is done page by page. However storing or retrieving data one page at a time is actually an advantage for many applications. Since you are often working with a large files such as  a phone, a song or an app.  So this is can be more efficient. The main draw back then of not being able to access bytes  individually is that nand flash can’t  be used to store a program code that you want to be executed in place. Since a CPU needs to read a single instruction, unless your CPU can specifically support this arrangement. There are a couple of downsize that the nand flash you maybe aware of however,  the first is in getting bit errors when you reading a page,  this is may not be a disater for musical file but obviously not acceptable for a data file or a backup for your image. To compensate for this , each page of flash has two sections,  the first is where your data is stored and the second is a smaller section is where error correction code is stored. There are differenct algorithm used to detect and correct for errors but the ideal is the data stored in ecc is used by the algorithm to detect errors  in the data,  and in some cases  correct an error in the data  field.  There is a limit to how much corruption can be detected, but minor errors such as a single bit error are dealt with regular basis without the application ever knowing it occurred. The second issue with nand to be aware of that it is more prone to developing a faulty bit. And this is caused an entire block to be declared as being bad, in fact even a new flash device will have a small percentage of blocks bad and over time some of the active blocks can be come bad. Circuitry in the flash device detects the block’s bad during erase or progam cycle and a bad block manager keeps track of this . Blocks of bad are automatically remapped, and since this happens behind,  the interface of software  doen’t know the difference. So to summarize the key differences between nor and nand, we saw you have to access data in pages with nand which is randly access in bytes . and there are differences in access time to erase, write and read from flash. The capacity  the flash  device contiues to rise for writes that is a steady rate,  but currently the largest nand devices have 10 times capacity of largest nor devices. And in terms of issues don’t impact the application code, we saw the nand flash requries bad block management  and error correction codes to deal with failure rate that experiences, the pin count is higher in nor given a type of interfaces has, which couple of with different capacity makes it more expencsive. And depending on how you using memory you maybe concered about the expected life cycle  of a chosen device . Eraing Flash Before getting into the driver though, the only other thing to cover you may come across when working with the flash has to do with the erase process, you may expect to read back the erased portion of memory has been all zeros but in fact  the erased flash memory has all bits set to the high state, so it read back the erased byte as being FF. When you write data to your address location  , the corresponing bits need to be zero are programed as logical zero and efficiently you can rewrite this location with first erase it providing you unwanted any of these bits transition from 0 to 1.  You can also write to a different address in the same block without first erasing block,  but in most cases you writing a large chunk of data, not a single byte,  and typically you don’t want to bother keeping in track of data   as being where to written to .  And for block should be erased before  write or not. This is what the driver does for you, which keeps your application quite simple, however,  be aware the overhead associated with the right command won’t  always be consistant.  As you sometimes you endure an erase and rewrite cycle, and other times you won’t. Where Flashx Driver Resides There are two groups of drivers in MQX, the first group contains io drivers, go through the io subsystem.  And it includs block mode drivers and byte mode drivers . The second group is a set of low level drivers such as the ADC and the lightweight GPIO driver. Since flash driver supports the writing and reading data of large chunks, it is categorized as blocked mode driver . In the SDK verison of MQX, the io sub system is limited. But the flash driver is still be considered as block mode driver. Similar to the structure of other drivers we’ve looked at, there is an upper layer and lower layer component in the flash driver. and before you can begin using any dirver, it has to be installed. If you selected flash using a configuation file, MQX will automaticly install the flash driver at boot up.  And when you install function is called,  the upper level will install function is passed a pointer to the low level configuration information. The installed function registered it’s called back function to the IO subsystem, once it’s associations are in place , your application code can use a normal a high level calls that access the flash device.  So for example,  before using the flash driver , you must open it , which will set up internal structures for the flash chip if hasn’t been opened before.  And will fetching the addressing for this device . You can then read from flash or write to it as you like using the high level commands. Accessing Flash Before getting further with using the driver though, it will be helpful to see how to access the flash itself.  The flash is organized to a series of blocks and you can structure those in different groups.  If you are using a kinetis processor, and using the flashx driver to access the internal flash, then as a minimum you need have a room for code base and reserve a saparate area for your data. You can also set your flash for equal size banks or however you wish to organize your  flash,  just keeping in mind the boundaries of these regions must be falled into block boundaries in the    flash . Each of these regions are effectively  a partition of the flash and the flashx driver refer to each partition  is a file or see in a monent the region of a flash you use for a file may not be continuously from address point of view , but for application point of view it can be considered to be continuous memory space. Accessing Flash Mqx maitans an index into a file and when you read from the file, the reading starts from an index, similarly, when you write to the file, it starts writing from the  index point , and the index  commands , as you wirte more data. Your application code can  adjust the location index, using  the fseek function , you maybe familiar with the fseek function found in a formatted  io section of starndard C library , and mqx’s fseek function is used in the same way. It can be used to set the index to provide  the offset from the beginning of a file, with an offset from the end of this file  , or to an offset in either  direction from the current position of the index. Data structures To understand flashx driver how it works , you need to farmilar with some key data structures that it uses. The first one to cover is the block info structure which defines how the flash is organnized. Some flash has different size blocks inside of it or maybe there is gaps between addressing . So this is a way of define a flash infrastructure. Your device will be represented by an array  or a block info structures,  one section for each section a  flash has continuous addressing  and all blocks  are in equal size.  The terminal is a bit  confusing here,  within each section of flash  there will be a number of blocks,  and the data structure   refers to is a  sector,   as mqx considers a sector to be the smallest eraseable units. The next element of this structure is the starting address of this section which is followed by the size section. The final element is reserved for any special flags and currently not being used. You can have a number of files in flash, the file block structure is used to define  a file, and it cantains a name for the file , the starting address for the file, and an ending address for the file, And the third data structure called the init structure is used to tie everything together , this contains a pointer to a array of block info structure, and a pointer to a array of file block structures, this also contains the base address of the flash device and some additional elements used to access the total flash address base . Flash Driver API So to summarized before we look  at the driver code, accessing the flash is very straight forward.  You must open the file  with the fopen function , and with the flashx driver , flags are not typically used.  To read from the file , you speciafy with reading data to be stored , and the number of bytes to read. And to write the flash you should provide  a pointer to the data to be written, and the numbe of bytes to transfer. And the last function we used, is the ioctl function, which can be used to retrieve or change the various parameters. When you using the ioctl function, you specify the command you want to use. And a point to where the result will place if you request a value as parameter . So what source code can you make .  you can retriev various values,  such as the base address, or the number of sectors.  You can flush the buffer, or control the buffering feature, erase all or part of flash chip, control the sector caching, or control the write protect. This document is the 19th Installment of the "Essentials of MQX RTOS Application Development" training course. Please watch the vedio for more details Essentials of MQX RTOS Application Development, Ses|NXP
View full article
This document shows how to use a mutex and semaphores in order to synchronize two tasks in a FreeRTOS and SDK 2.0 project. For this example it is used SDK 2.0, TWR-K64F120M, and FreeRTOS. If you want to know how to create a new SDK 2.0 with FreeRTOS project please check the below link: https://community.freescale.com/docs/DOC-330183 MUTEX EXAMPLE: Introduction A mutex provides mutual exclusion among tasks, when they access a shared resource. When used for mutual exclusion the mutex acts like a token that is used to guard a resource. When a task wishes to access the resource it must first obtain ('take') the token. When it has finished with the resource it must 'give' the token back - allowing other tasks the opportunity to access the same resource. Mutexes cannot be used in interrupt service routines. Mutexes use the same semaphore access API functions. Writing a Mutex example code The mutex example code is used to demonstrate how to use a mutex to synchronize two tasks. It creates a mutex and two tasks. Both tasks use PRINTF to print out messages. Each task will lock the mutex before printing and unlock it after printing to ensure that the outputs from tasks are not mixed together. According with this proposal it is necessary to follow the below steps. In main function, create a mutex using the xSemaphoreCreateMutex() API. This API creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines. xMutex = xSemaphoreCreateMutex(); Create two tasks with the same priority, these tasks will use PRINTF to print out messages.        xTaskCreate(write_task_1,"write_task_1",configMINIMAL_STACK_SIZE,NULL,                      task_PRIORITY, NULL);        xTaskCreate(write_task_2,"write_task_2",configMINIMAL_STACK_SIZE,NULL,                      task_PRIORITY, NULL); The two print tasks both use the PRINTF. If they used it in the same time, there would be conflicts, so a mutex is used to synchronize the two tasks. Each print task will try to lock the mutex before printing the message, using the macro xSemaphoreTake (SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait); it will wait for the mutex as long as needed. Once the mutex is locked it prints the message and then unlocks the mutex  with the macro xSemaphoreGive (SemaphoreHandle_t xSemaphore) so that the other task can lock it. This process is repeated indefinitely. static void write_task_1(void *pvParameters) {     while (1)     { xSemaphoreTake(xMutex, portMAX_DELAY);         PRINTF("Hello, this is the |");         taskYIELD();         PRINTF("first task \r\n"); xSemaphoreGive(xMutex);         taskYIELD();     } } static void write_task_2(void *pvParameters) { while (1) { xSemaphoreTake(xMutex, portMAX_DELAY); PRINTF("And now this is the |"); taskYIELD(); PRINTF(" second task\r\n"); xSemaphoreGive(xMutex); taskYIELD(); } } At this point you can build and debug the example. Complete Code /* Kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "timers.h" #include "semphr.h" /* Freescale includes. */ #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "board.h" #include "pin_mux.h" #include "clock_config.h" /******************************************************************************* * Definitions ******************************************************************************/ SemaphoreHandle_t xMutex; /******************************************************************************* * Prototypes ******************************************************************************/ static void write_task_1(void *pvParameters); static void write_task_2(void *pvParameters); /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Main function */ int main(void) { xMutex = xSemaphoreCreateMutex(); BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); xTaskCreate(write_task_1, "WRITE_TASK_1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(write_task_2, "WRITE_TASK_2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); /* Start scheduling. */ vTaskStartScheduler(); for (;;) ; } /*! * @brief Write Task 1 function */ static void write_task_1(void *pvParameters) { while (1) { xSemaphoreTake(xMutex, portMAX_DELAY); PRINTF("Hello, this is the "); taskYIELD(); PRINTF("first task \r\n"); xSemaphoreGive(xMutex); taskYIELD(); } } /*! * @brief Write Task 2 function */ static void write_task_2(void *pvParameters) { while (1) { xSemaphoreTake(xMutex, portMAX_DELAY); PRINTF("And now this is the "); taskYIELD(); PRINTF(" second task\r\n"); xSemaphoreGive(xMutex); taskYIELD(); } } SEMAPHORE EXAMPLE: Introduction Binary semaphores and mutexes are very similar but have some subtle differences: Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the better choice for implementing synchronisation (between tasks or between tasks and an interrupt), and mutexes the better choice for implementing simple mutual exclusion. A semaphore can be used in order to control the access to a particular resource that consists of a finite number of instances. Writing a Semaphore example code After install SDK 2.0 you can find a semaphore example at the path: <SDK_install_path>\SDK_2.0_xxx\boards\<your_name>\rtos_examples\freertos_sem The example uses four tasks. One producer_task and three consumer_tasks. The producer_task starts by creating of two semaphores (xSemaphore_producer and xSemaphore_consumer). These semaphores control access to virtual item. The synchronization is based on bilateral rendezvous pattern. Both of consumer and producer must be prepared to enable transaction. Here’s the API (copied from the FreeRTOS website): MODULES xSemaphoreCreateBinary SemaphoreHandle_t xSemaphoreCreateBinary( void ); Creates a binary semaphore, and returns a handle by which the semaphore can be referenced. xSemaphoreCreateBinaryStatic SemaphoreHandle_t xSemaphoreCreateBinaryStatic(                           StaticSemaphore_t *pxSemaphoreBuffer ); Creates a binary semaphore, and returns a handle by which the semaphore can be referenced. xSemaphoreCreateCounting SemaphoreHandle_t xSemaphoreCreateCounting(                                             UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced. xSemaphoreCreateCountingStatic SemaphoreHandle_t xSemaphoreCreateCountingStatic(                                  UBaseType_t uxMaxCount,                                  UBaseType_t uxInitialCount StaticSemaphore_t pxSempahoreBuffer ); Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced. xSemaphoreCreateMutex SemaphoreHandle_t xSemaphoreCreateMutex( void ) Creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines. xSemaphoreCreateMutexStatic SemaphoreHandle_t xSemaphoreCreateMutexStatic(                             StaticSemaphore_t *pxMutexBuffer ); Creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines. xSemaphoreCreateRecursiveMutex SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void ) Creates a recursive mutex, and returns a handle by which the mutex can be referenced. Recursive mutexes cannot be used in interrupt service routines. configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateRecursiveMutex() to be available. xSemaphoreCreateRecursiveMutexStatic SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer ) Creates a recursive mutex, and returns a handle by which the mutex can be referenced. Recursive mutexes cannot be used in interrupt service routines. configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateRecursiveMutexStatic() to be available. vSemaphoreDelete void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ); Deletes a semaphore, including mutex type semaphores and recursive semaphores. Do not delete a semaphore that has tasks blocked on it (tasks that are in the Blocked state waiting for the semaphore to become available). xSemaphoreGetMutexHolder TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex ); Return the handle of the task that holds the mutex specified by the function parameter, if any. xSemaphoreGetMutexHolder() can be used reliably to determine if the calling task is the mutex holder, but cannot be used reliably if the mutex is held by any task other than the calling task. xSemaphoreTake xSemaphoreTake( SemaphoreHandle_t xSemaphore,                  TickType_t xTicksToWait ); Macro to obtain a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or xSemaphoreCreateCounting(). xSemaphoreTakeFromISR xSemaphoreTakeFromISR(         SemaphoreHandle_t xSemaphore,         signed BaseType_t *pxHigherPriorityTaskWoken ) A version of xSemaphoreTake() that can be called from an ISR. Unlike xSemaphoreTake(), xSemaphoreTakeFromISR() does not permit a block time to be specified. xSemaphoreTakeRecursive xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,                          TickType_t xTicksToWait ); Macro to recursively obtain, or 'take', a mutex type semaphore. The mutex must have previously been created using a call to xSemaphoreCreateRecursiveMutex(); configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available. xSemaphoreGive xSemaphoreGive( SemaphoreHandle_t xSemaphore ); Macro to release a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or xSemaphoreCreateCounting(), and obtained using sSemaphoreTake(). xSemaphoreGiveRecursive xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex ) Macro to recursively release, or 'give', a mutex type semaphore. The mutex must have previously been created using a call to xSemaphoreCreateRecursiveMutex(); configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available. xSemaphoreGiveFromISR xSemaphoreGiveFromISR(         SemaphoreHandle_t xSemaphore,         signed BaseType_t *pxHigherPriorityTaskWoken) Macro to release a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting(). Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) must not be used with this macro. uxSemaphoreGetCount UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore ); Returns the count of a semaphore. Enjoy!!!
View full article
MQXv5 is Coming! NXP has teamed up with Embedded Access to continue active development of MQX software solutions, providing regular updates, enhancements and ports to new processors. With the introduction of MQX v5, an extension to MQX Classic v4.2, and with new commercial licensing, developers can continue to use MQX with the latest Kinetis, i.MX, and other processors. Compare MQX Classic and MQX v5 by visiting nxp.com/MQX. Then, give us your feedback on which devices and features you’d like supported in this newest addition, MQX v5. Note, the first MQX v5 products are expected to be available near the end of Q3, 2016. MQX v5 products will be purchasable at nxp.com/mqxv5 and through distribution partners.
View full article
A new patch, MQX v4.2.0.2, is now available at www.nxp.com/mqxclassic​.This release comes in one download that contains both .zip packages and patch files. See the Release Notes (attached) for a full list of issues that are fixed in this release. The Release Notes also contain instructions for how to install via the .zip or patch files. To Download the patch: 1. go to www.nxp.com/mqxclassic 2. Click the "Download" button (below the Overview paragraph) -- you may be prompted to Sign In 3. Click on "MQX RTOS v4.2 releases and patches" 4. Review and click through the license agreement 5. Click on "MQX 4.2.0.2 Patch.zip"
View full article
If you have noticed many TCP Retransmission, Out Of Order or Duplicate Acknowledge packets while running a TCP/IP application based on MQX RTCS then you may be interested in this article. After some investigation it comes to be that the default value of global variable _TCP_rto_min may cause this congestion depending on your application. Finally this problem was solved by setting a new value to this variable after calling function RTCS_create(). This article explains what is behind this behavior and how _TCP_rto_min affects the performance in an application using RTCS.
View full article
NXP provides a software driver library for their Kinetis ARM Cortex-M0 and M4 devices, the ‘Kinetis SDK’, available from http://www.nxp.com/ksdk.   The below link provides information about how download a KSDK package, how to install KSKD v2.0 project wizard in Kinetis Design Studio (KDS), and how to create a KSDK v2.0 project. Using Kinetis Design Studio v3.x with Kinetis SDK v2.0 NOTE: Before you continue with this document, it is important to download and install KSDK v2.0. The purpose of this document is to provide information that enables developers to start their first application using FreeRTOS and KSDK v2.0. Creating a new FreeRTOS with KSDK V2.0 application. The following steps show how to create a new FreeRTOS project in KDS using KSDK v2.0. 1. Open Kinetis Design Studio. 2. Go to 'File' menu and click on File->New->Kinetis SDK 2.x Project 3. Select a project name and the Kinetis SDK folder then click 'Next' 4. Select the processor or board to be used, in addition it is important to include all SDK drivers and add FreeRTOS to the project and click 'Finish' 5. In the project created you can see the following folder structure: 6. The main.c file is a template for main module created by new Kinetis SDK 2.0 Project Wizard, this contains a task responsible of printing "Hello world." message. 7. If you want to build and debug this example uncomment the next lines: #include "fsl_debug_console.h" and PRINTF("Hello world.\r\n"); 8. Build and debug. Developing the first FreeRTOS with KSDK V2.0 application. This section describes the creation of a simple application that blinks LEDs on the TWR-K64F120M board. After a new project is created, in the main function the following routines are called in order to initialize the board hardware: BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); By default only the UART0 is initialized in order to use it as debug console. Also in main it is created a task (hello_task) using xTaskCreate () function. xTaskCreate () creates a new task and adds it to the list of tasks that are ready to run; it contains the following parameters: pvTaskCode. Pointer to the task entry function. Tasks must be implemented to never return. pcName. A descriptive name for the task. This is mainly used to ease debugging. Max length defined by configMAX_TASK_NAME_LEN. usStackDepth. The size of the task stack specified as the number of variables the stack can hold - not the number of bytes. For example, if the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes will be allocated for stack storage. The stack depth multiplied by the stack width must not exceed the maximum value that can be contained in a variable of type size_t. pvParameters. Pointer that will be used as the parameter for the task being created. uxPriority. The priority at which the task should run. pvCreatedTask. Used to pass back a handle by which the created task can be referenced. Writing the application. The TWR-K64F120M contains 4 LED's connected to GPIO signals (optionally isolated using jumpers): — Green LED (D5) to PTE6 — Yellow LED (D6) to PTE7 — Orange LED (D7) to PTE8 — Blue LED (D9) to PTE9 For this example it is used the TWR-K64F120M board, however if you are using the FRDM-K64F the RGB LED is connected through GPIO signals: — RED to PTB22 — BLUE to PTB21 — GREEN to PTE26 To initialize the GPIO, enable the port clock, define a pin configuration, either input or output, in the pin_mux.c file, as is described in the below steps: Open the pin_mux.c file.    2. Enable the port clock.      CLOCK_EnableClock(kCLOCK_PortE);    3. Configure these pins as GPIO signals.       PORT_SetPinMux(PORTE, 6u, kPORT_MuxAsGpio);     PORT_SetPinMux(PORTE, 7u, kPORT_MuxAsGpio);     PORT_SetPinMux(PORTE, 8u, kPORT_MuxAsGpio);     PORT_SetPinMux(PORTE, 9u, kPORT_MuxAsGpio); Then, in main function create 5 tasks, one to initialize the GPIO driver and the other to blink the LEDs. You can find the complete code at the end of this document.   /* Create RTOS task */ xTaskCreate(init_task, "Init_task", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_blue, "Task_blue", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_orange, "Task_orange", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_yellow, "Task_yellow", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_green, "Task_green", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); Write the code of each task. 1. init_task function. In this function are initialized the GPIO pins as output using the gpio_pin_config_t structure then it is called the GPIO_PinInit() function for each GPIO pins.      The GPIO_PinInit() parameters are: base. GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) pin. GPIO port pin number. config. GPIO pin configuration pointer.      Finally call vTaskSuspend(), this function suspend the task. When a task is suspended, it will never get back to execution unless it is explicitly set in Ready state by another task.      The code for init_task function is:      gpio_pin_config_t ledB_config = {                       kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledO_config = {                          kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledG_config = {                      kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledY_config = {                       kGPIO_DigitalOutput, 0,                   };       /* Init output LED GPIO. */     GPIO_PinInit(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN, &ledB_config);     GPIO_PinInit(BOARD_LED_ORANGE_GPIO, BOARD_LED_ORANGE_GPIO_PIN, &ledO_config);     GPIO_PinInit(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, &ledG_config);     GPIO_PinInit(BOARD_LED_YELLOW_GPIO, BOARD_LED_YELLOW_GPIO_PIN, &ledY_config);     vTaskSuspend(NULL); 2. task_blue, task_orange, task_yellow, task green functions. It is necessary to write the code of each task. Each task uses LED_XXX_TOGGLE() and vTaskDelay (), to toggle a LED, this should be in a infinite loop.      Below is the code for the task_blue function:      while (1)        {                         /* Toggle LED BLUE */               LED_BLUE_TOGGLE();               vTaskDelay( 500 );        } Finally build and debug the project.  Enjoy! Complete Code main.c #include <string.h> #include "board.h" #include "pin_mux.h" #include "clock_config.h" #include "fsl_debug_console.h" /* FreeRTOS kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "timers.h" /* Task priorities. */ #define task_PRIORITY (configMAX_PRIORITIES - 1) static void init_task(void *pvParameters) {        /* Init output LED GPIO. */          gpio_pin_config_t ledB_config = {                       kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledO_config = {                          kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledG_config = {                      kGPIO_DigitalOutput, 0,                   };          gpio_pin_config_t ledY_config = {                       kGPIO_DigitalOutput, 0,                   };        /* Init output LED GPIO. */                   GPIO_PinInit(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN, &ledB_config);                   GPIO_PinInit(BOARD_LED_ORANGE_GPIO, BOARD_LED_ORANGE_GPIO_PIN, &ledO_config);                   GPIO_PinInit(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, &ledG_config);                   GPIO_PinInit(BOARD_LED_YELLOW_GPIO, BOARD_LED_YELLOW_GPIO_PIN, &ledY_config);                   vTaskSuspend(NULL); } static void task_blue(void *pvParameters) {         while (1)        {        /* Toggle LED BLUE */               LED_BLUE_TOGGLE();               vTaskDelay( 500 );        } } static void task_orange(void *pvParameters) {         while (1)        {        /* Toggle LED ORANGE */               LED_ORANGE_TOGGLE();               vTaskDelay( 500 );        } } static void task_yellow(void *pvParameters) {         while (1)        {        /* Toggle LED YELLOW */               LED_YELLOW_TOGGLE();               vTaskDelay( 500 );        } } static void task_green(void *pvParameters) {         while (1)        {        /* Toggle LED GREEN */               LED_GREEN_TOGGLE();               vTaskDelay( 500 );        } } int main(void) { /* Init board hardware. */ BOARD_InitPins();   // This function initializes the pins used in this example BOARD_BootClockRUN(); BOARD_InitDebugConsole();   /* Create RTOS task */ xTaskCreate(init_task, "Init_task", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_blue, "Task_blue", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_orange, "Task_orange", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_yellow, "Task_yellow", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); xTaskCreate(task_green, "Task_green", configMINIMAL_STACK_SIZE, NULL, task_PRIORITY, NULL); vTaskStartScheduler(); for(;;) { /* Infinite loop to avoid leaving the main function */ __asm("NOP"); /* something to use as a breakpoint stop while looping */ } } Complete Code  pin_mux.c #include "fsl_device_registers.h" #include "fsl_port.h" #include "pin_mux.h" /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Initialize all pins used in this example * * @param disablePortClockAfterInit disable port clock after pin * initialization or not. */ void BOARD_InitPins(void) { /* Ungate the port clock */ CLOCK_EnableClock(kCLOCK_PortC); CLOCK_EnableClock(kCLOCK_PortE); /* Affects PORTC_PCR3 register */ PORT_SetPinMux(PORTC, 3u, kPORT_MuxAlt3); /* Affects PORTC_PCR4 register */ PORT_SetPinMux(PORTC, 4u, kPORT_MuxAlt3); PORT_SetPinMux(PORTE, 6u, kPORT_MuxAsGpio); PORT_SetPinMux(PORTE, 7u, kPORT_MuxAsGpio); PORT_SetPinMux(PORTE, 8u, kPORT_MuxAsGpio); PORT_SetPinMux(PORTE, 9u, kPORT_MuxAsGpio); }
View full article