Saturday, January 30, 2016

Updated MQX 4.1.0 with rpmsg

Open-Amp and MQX 4.1.0

The latest release from NXP is a port of the FreeRTOS operating system to the imx6sx SOC and imx7 SOC.  This release has rpmsg/open-amp along with drives and examples.  Also, here is a good overview of open-amp located here.  MQX uses MCC; until now, spend a few days last week porting rpmsg delivered by NXP to MQX 4.1.0.  FreeRTOS example is portable to MQX.    The main difference in porting open-amp to MQX, is the ISR only posts the channel message to a queue instead of calling open-amp stack and processing the message in the ISR. There are still some open issues; but it is working.

At this time I don't know if it is possible to release the code due to all of the licensing issues; still need to see if it is possible;





Saturday, January 23, 2016

How to reload the same firmware on the Neo M4 without a reboot

Reloading M4 without rebooting on the UDOO Neo


Most of the time I have to modify and reload firmware on the M4 many times during a debug session, i.e adding debug code or features etc, and each time when reloading firmware the Neo must reboot each time.  This gets old; plus all of the time wasted.

So, what is causes the firmware not to be reloaded? Well that is simple, it is the memory protection setup on the RDC, one simple way to to reload firmware to turn off the RDC protection, another way, just add a compile option and not enable RDC memory protection.

For MQX, it is in the init_hardware.c file, function void rdc_init_memory(void) so, I added a simple #ifdef and allows the code to be reloaded.

void RDC_memory_init(void)
{
    uint32_t start, end;
#if defined(__CC_ARM)
    extern uint32_t Image$$VECTOR_ROM$$Base[];
    extern uint32_t Image$$ER_m_text$$Limit[];
    extern uint32_t Image$$RW_m_data$$Base[];
    extern uint32_t Image$$RW_m_data$$Limit[];

    start = (uint32_t)Image$$VECTOR_ROM$$Base & 0xFFFFF000;
    end = (uint32_t)(Image$$ER_m_text$$Limit + (Image$$RW_m_data$$Limit - Image$$RW_m_data$$Base));
    end = (end + 0xFFF) & 0xFFFFF000;
#else
    extern uint32_t __FLASH_START[];
    extern uint32_t __FLASH_END[];

    start = (uint32_t)__FLASH_START & 0xFFFFF000;
    end   = ((uint32_t)__FLASH_END + 0xFFF) & 0xFFFFF000;
#endif
#if _DEBUG_
#pragma message "Turned off memory protection"
#else
    RDC_SetMrAccess(RDC, rdcMrMmdc, start, end, (3 << (BOARD_DOMAIN_ID * 2)), true, false);    
#endif
}


When compiling just define _DEBUG_ and  load the app.

video

Sunday, January 17, 2016

Udoo Neo M4 memory layout and performance

The M4 has several non-contiguous memory blocks for code and data

  • TCM (tightly coupled memory)
    • TCMU
      • This is 32K SRAM for Code
    • TCML
      • This is 32K SRAM for Data
  • OCRAM
    • (Need to look into how much can be access TBD)
  • DDR
    • Linux sets aside 8MB 
      • A9 and M4 must share this RAM 
    • The last 1MB is used for MCC/RPMSG
  • SPI Flash

The application baseflight port will be more then 32K of text (code)  So, the code must be in one memory or split.  

Using a split method requires some up front work with the linker file and the loader.  It is possible to create a linker file putting some code in TCMU and DDR.  The idea being RTOS, interrupt; code which has a high bandwidth rate.  Less bandwidth code would go into DDR, or even OCRAM or SPI flash.

Here is an example of a loader file:


/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x9ff00000, LENGTH = 0x00008000
  m_text                (RX)  : ORIGIN = 0x84000000, LENGTH = 0x00040000
  m_data                (RW)  : ORIGIN = 0x84040000, LENGTH = 0x00028000
}

__FLASH_START = ORIGIN(m_interrupts);
__FLASH_END   = ORIGIN(m_text) + LENGTH(m_text);

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into Flash */
  .interrupts :
  {
    __VECTOR_TABLE = .;
    . = ALIGN(4);
    KEEP(*(.isr_vector))     /* Startup code */
    . = ALIGN(4);
    *croutine.c.obj (.text .text*)
    *event_groups.c.obj (.text .text*)
    *list.c.obj (.text .text*)
    *queue.c.obj (.text .text*)
    *tasks.c.obj (.text .text*)
    *timers.c.obj (.text .text*)
    *port.c.obj (.text .text*)
    *startup_MCIMX6X_M4.S.obj (.text .text*)
    *system_MCIMX6X_M4.c.obj (.text .text*)
    *uart_imx.c.obj (.text .text*)
    *mu_imx.c.obj (.text .text*)
    *heap_2.c.obj (.text .text*)
    *rpmsg_rtos.c.obj (.text .text*)
    *platform.c.obj (.text .text*)
    *hil.c.obj (.text .text*)
    *sh_mem.c.obj (.text .text*)
    *remote_device.c.obj (.text .text*)
    *rpmsg.c.obj (.text .text*)
    *rpmsg_ext.c.obj (.text .text*)
    *rpmsg_core.c.obj (.text .text*)
    *rpmsg_porting.c.obj (.text .text*)
    
    *baseflight.c.obj (.text .text*)
    
  } > m_interrupts

  /* The program code and other data goes into Flash */
  .text :
  {
    . = ALIGN(4);
    *(.text)                 /* .text sections (code) */
    *(.text*)                /* .text* sections (code) */
    *(.rodata)               /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)               /* glue arm to thumb code */
    *(.glue_7t)              /* glue thumb to arm code */
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
  } > m_text


The m_interrupt section, need to call out the file name with the text, this will move the code into the section.  So, for slow code put in DDR. 

When creating a binary file, the code is it two separate sections:

  m_interrupts          (RX)  : ORIGIN = 0x9ff00000, LENGTH = 0x00008000
  m_text                (RX)  : ORIGIN = 0x84000000, LENGTH = 0x00040000

so, the binary will span from 0x84000000 to 0x9FF08000.  So, to fix this, must use a Intel Hex file. The Intel hex file will only create records for the sections that need to be fixed with data.

So, a M4 loader now must able to load intel hex files into memory.

Also, the next pass will move .data sections into SRAM along with the stack. 





Sunday, January 3, 2016

UDOO Neo and openocd working

With the help of IIRC openocd able to create a configuration file for openocd to connect to the M4 DAP and able to halt and reset just the M4 processor.

I'm using an old Amontec JTAGkey (using FTDI 232 chip) here is a photos of the wiring.


Using the imx6sx.cfg file and the following command to connect to M4.

sudo  ./src/openocd -f interface/ftdi/jtagkey.cfg -f ./tcl/target/imx6sx.cfg

Output:

Open On-Chip Debugger 0.10.0-dev-00023-g8590315 (2016-01-02-19:34)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 1000 kHz
Warn : imx6sx.sdma: nonstandard IR value
Warn : imx6sx.sjc: nonstandard IR value
imx6sx.dapM4
Info : clock speed 1000 kHz
Info : JTAG tap: imx6sx.dapM4 tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Info : JTAG tap: imx6sx.dapA9 tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Info : TAP imx6sx.sdma does not have IDCODE
Info : JTAG tap: imx6sx.sjc tap/device found: 0x0891c01d (mfg: 0x00e, part: 0x891c, ver: 0x0)
Info : imx6sx.dapM4: hardware has 6 breakpoints, 4 watchpoints


Then start a gdb session:
./arm-none-eabi-gdb

(gdb) tar ext :3333   <---- connects to openocd
Remote debugging using :3333
(gdb)  monitor  halt    <------------- halts only M4
(gdb)  monitor  reset   <------------ reset M4 (resets the M4 and restarts from 0x0)

Next will rebuild and see if M4 will single step...