Picking Tennis via Dual-Core IPC
Table of Contents
1 Present Build
This is the draft Tennis Picking Roving platform under construction.
The PSoC 62S4 Dev Board is fixed on crawler-type moving plat and there are three 6V DC motor to be controlled for moving and pick action.
Obviously, this is uncompleted project , since the core part - machine learing on object detection is too challengous to be completed to catch the DDL.
But the conclustion can be positive, this PSoC 62S4 dev board under Modus Toolbox IDE altogether provide perfect application scenary for Smart Edge computing.
Due to .......
2 IPC control with Sharedmemory
As has mentioned before, IPC semaphore can be used as toggled switch for CM0+ and CM4 cores to access shared resources for peripheral or CPU resources. It is good to use IPC pipes only for large data steam. Shared memory fits for most cases.
2.1 The linking script shall be revised for address and size in CM0+ linker.ld
/* The MEMORY section below describes the location and size of blocks of memory in the target. * Use this section to specify the memory regions available for allocation. */ MEMORY { /* The ram and flash regions control RAM and flash memory allocation for the CM0+ core. * You can change the memory allocation by editing the 'ram' and 'flash' regions. * Note that 2 KB of RAM (at the end of the SRAM) are reserved for system use. * Using this memory region for other purposes will lead to unexpected behavior. * Your changes must be aligned with the corresponding memory regions for the CM4 core in 'xx_cm4_dual.ld', * where 'xx' is the device group; for example, 'cy8c6xx7_cm4_dual.ld'. */ ram (rwx) : ORIGIN = 0x08000000, LENGTH = 0x1F00 flash (rx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* This is an unprotected public RAM region, with the placed .cy_sharedmem. * This region is used to place objects that require full access from both cores. * Uncomment the following line, define the region origin and length, and uncomment the placement of * the .cy_sharedmem section below. */ /* public_ram (rw) : ORIGIN = %REGION_START_ADDRESS%, LENGTH = %REGION_SIZE% */ public_ram (rw) : ORIGIN = 0x08001F00, LENGTH = 0x0100 /* The following regions define device specific memory regions and must not be changed. */ sflash_user_data (rx) : ORIGIN = 0x16000800, LENGTH = 0x800 /* Supervisory flash: User data */ sflash_nar (rx) : ORIGIN = 0x16001A00, LENGTH = 0x200 /* Supervisory flash: Normal Access Restrictions (NAR) */ sflash_public_key (rx) : ORIGIN = 0x16005A00, LENGTH = 0xC00 /* Supervisory flash: Public Key */ sflash_toc_2 (rx) : ORIGIN = 0x16007C00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 */ sflash_rtoc_2 (rx) : ORIGIN = 0x16007E00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 Copy */ xip (rx) : ORIGIN = 0x18000000, LENGTH = 0x8000000 /* 128 MB */ efuse (r) : ORIGIN = 0x90700000, LENGTH = 0x100000 /* 1 MB */ }
and
/* To use unprotected public RAM, uncomment the following .cy_sharedmem section placement.*/ /* .cy_sharedmem (NOLOAD): { . = ALIGN(4); __public_ram_start__ = .; KEEP(*(.cy_sharedmem)) . = ALIGN(4); __public_ram_end__ = .; } > public_ram */ .cy_sharedmem (NOLOAD): { . = ALIGN(4); __public_ram_start__ = .; KEEP(*(.cy_sharedmem)) . = ALIGN(4); __public_ram_end__ = .; } > public_ram
The cm4 core linker.ld remain unchanged.
MEMORY { /* The ram and flash regions control RAM and flash memory allocation for the CM4 core. * You can change the memory allocation by editing the 'ram' and 'flash' regions. * Note that 2 KB of RAM (at the end of the SRAM) are reserved for system use. * Using this memory region for other purposes will lead to unexpected behavior. * Your changes must be aligned with the corresponding memory regions for CM0+ core in 'xx_cm0plus.ld', * where 'xx' is the device group; for example, 'cy8c6xx7_cm0plus.ld'. */ ram (rwx) : ORIGIN = 0x08002000, LENGTH = 0x1D800 flash (rx) : ORIGIN = 0x10000000, LENGTH = 0x40000 /* The following regions define device specific memory regions and must not be changed. */ sflash_user_data (rx) : ORIGIN = 0x16000800, LENGTH = 0x800 /* Supervisory flash: User data */ sflash_nar (rx) : ORIGIN = 0x16001A00, LENGTH = 0x200 /* Supervisory flash: Normal Access Restrictions (NAR) */ sflash_public_key (rx) : ORIGIN = 0x16005A00, LENGTH = 0xC00 /* Supervisory flash: Public Key */ sflash_toc_2 (rx) : ORIGIN = 0x16007C00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 */ sflash_rtoc_2 (rx) : ORIGIN = 0x16007E00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 Copy */ xip (rx) : ORIGIN = 0x18000000, LENGTH = 0x8000000 /* 128 MB */ efuse (r) : ORIGIN = 0x90700000, LENGTH = 0x100000 /* 1 MB */ }
The shared memory is allocated with fixed address,and make it writable with attribute of (rwx)
public_ram (rwx) : ORIGIN = 0x08001F00, LENGTH = 0x0100
2.2 Revise the makfile in CM0+ and add definations to allocate for cm0+ and shared memory in RAM.
# Add additional defines to the build process (without a leading -D). DEFINES+=CY_CORTEX_M4_APPL_ADDR=CY_FLASH_BASE+0x4400U
2.3 Coding
In cm0, assign the variable with direct address and right size.
#define IPC_ADDR 0x08001F00 uint16_t ipc_value, cm0_value; cm0_value = 0x00; (*((uint16_t *)(IPC_ADDR)) = (uint16_t)(cm0_value));
Do the same in cm4 core ,
uint16_t ipc_value, cm4_value; cm4_value = 0x00;
Here is the IPC semaphore read ipc_value in cm0
for (;;) { /* Check if the button is pressed */ if (Cy_GPIO_Read(CYBSP_SW2_PORT, CYBSP_SW2_PIN) == 0) { #if ENABLE_SEMA if (Cy_IPC_Sema_Set(SEMA_NUM, false) == CY_IPC_SEMA_SUCCESS) #endif { /* Print a message to the console */ Cy_SCB_UART_PutString(CYBSP_UART_HW, "Message sent from CM0+\r\n");cyhal_system_delay_ms(MOTOR_ON_DURATION); ipc_value = (*(( uint16_t *)(IPC_ADDR))); #if ENABLE_SEMA while (CY_IPC_SEMA_SUCCESS != Cy_IPC_Sema_Clear(SEMA_NUM, false)); #endif } } }
and in cm4, write ipc_value
{ if (cyhal_gpio_read(CYBSP_USER_BTN) == CYBSP_BTN_PRESSED) { #if ENABLE_SEMA /* Attempt to lock the semaphore */ if (Cy_IPC_Sema_Set(SEMA_NUM, false) == CY_IPC_SEMA_SUCCESS) #endif { /* Print a message to the console */ printf("Message sent from CM4\r\n"); (*((uint16_t *)(IPC_ADDR)) = (uint16_t)(ipc_value)); ipc_value++; #if ENABLE_SEMA while (CY_IPC_SEMA_SUCCESS != Cy_IPC_Sema_Clear(SEMA_NUM, false)); #endif } }
2.4 The ipc_value can be assiged bit-wise control for three motors in movement control
typedef enum { M1A_LEFT, M1B_RIGHT, M2A_FORWARD, M2B_BACKWARD, M3A_PICK, M3B_RELEASE, LED1_ONOFF, LED2_ONOFF, } mov_ctl_t;
3 Control Motor in CM0+
3.1 The motors is controlled in cm0 core in polling or interrupt mode, according to the ipc_value in unsigned 16 bit integer format, the case-switch selection can be used as action code
void process_ipc(uint16_t mov_command) { //char str[0]; str[0]=ipc_value+0x30; Cy_SCB_UART_PutString(CYBSP_UART_HW, str); uint32_t mov; switch(mov_command) { /* Move Command cycle */ case M1A_LEFT: mov = M0A; break; case M1B_RIGHT: mov =M0B; break; case M2A_FORWARD: mov =M1A; break; case M2B_BACKWARD: mov =M1B; break; case M3A_PICK: mov =M2A; break; case M3B_RELEASE: mov =M2B; break; case LED1_ONOFF: //Not connected mov =MOVINT; break; case LED2_ONOFF: mov =MOVINT; break; /* Default nope action */ default: mov = MOVINT; //Not connected //print_instructions(); return; } motor_ctl(mov); }
That part is short and simple,
3.2 There are 6 pins needed for motor control
#define M0A (P10_0) //A0 #define M0B (P10_1) //A1 #define M1A (P10_2) //A2 #define M1B (P10_3) //A3 #define M2A (P9_0) //J2_0 #define M2B (P9_1) //J2_1 #define MOVINT (P9_2) //J2_4
Motor control with chal_gpio_write,
void motor_ctl(uint32_t pinNum){ cyhal_gpio_write(pinNum, CYBSP_MOTOR_STATE_ON); cyhal_system_delay_ms(MOTOR_ON_DURATION); cyhal_gpio_toggle(pinNum); }
4 Machine Learning in CM4
4.1 The most challengour part is ML, there is unexpected issue with uncompatible model versioning , without any useful guidance, this nearlly ruin alll the effort
{gallery}Version issues |
---|
1 |
2 |
3 |
4 |
Fortunately, I made it in the end by reading code and find out how to make revision to codes.
4.2 As mentioned in previous blog Tennis Picker@The Core#4 The ML configuration and Obeject Detection . The ML configurator can be of good help.
This project can be running under magic wand model to detect gyro-sensors. But it is not possible with image detection with availble ML model of MobileNetv1_FPN, sizing 6M.
Availible Flash size of 256K in PSoC 62S4, the model shall be put in external memory, refer to xip example on how to use external memory.
Meanwhile I have to reduce the model size in new training according to https://keras.io/examples/vision/retinanet/ .
This part need more resources and computing capability, it is still on the way.
5 Summary
This AT the Core design challenge is one of most difficult one for me. Since I have proposed one difficult target and only half way before deadline.
That is still worth it. Since I have explored PSoC 62S4 Pioneer Kit with Modus Toolbox IDE, that would be perfect for most embedded project with amazing capabilities and easy-deployed toolsets, expecially that of ML configurator.
Even the project is not completed, it can still show that my previous proposal is valid one and can be made if more time spent. I shall continue the train new model fit for this memory size. After that I shall deploy the machine learning model again to find out how it goes.