Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FreeRTOS Dual-Core Capability (ICC) to v2 #406

Draft
wants to merge 6 commits into
base: v2-staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions sdk/freertos_app_cpu0/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ int main(void)
__asm__("sev");
#endif

Xil_ExceptionInit();
intr_init();
icc_init();
vPortInstallFreeRTOSVectorTable();
Expand All @@ -148,14 +147,12 @@ int main(void)

const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS);

xil_printf("CPU0 - Hello from FreeRTOS example main()!\r\n");

/* Create the three tasks */
xTaskCreate(prvTxTask, /* The function that implements the task. */
(const char *) "CPU0_Tx", /* Text name for the task, provided to assist debugging only. */
configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */
NULL, /* The task parameter is not used, so set to NULL. */
tskIDLE_PRIORITY, /* The task runs at the idle priority. */
tskIDLE_PRIORITY,
&xTxTaskHandle);

xTaskCreate(prvRxTask, /* The function that implements the task. */
Expand Down Expand Up @@ -233,15 +230,18 @@ static void prvTxTask(void *pvParameters)
// HWstring, /* The address of the data being sent. */
// 0UL); /* The block time. */

xil_printf("DEBUG: CPU 0 about to attempt send\r\n");
// xil_printf("DEBUG: CPU0 about to attempt send\r\n");
xil_printf("A\r\n");

// Send a message to the other core
size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBuffer, HWstring, sizeof(HWstring), 0UL);
size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBufferHandle, HWstring, sizeof(HWstring), 0UL);

xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent);
// xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent);
xil_printf("B\r\n");

if (bytes_sent == 0) {
xil_printf("ERROR: CPU 0 failed to write to ICC buffer\r\n");
// xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n");
xil_printf("C\r\n");
}
}
}
Expand All @@ -263,17 +263,21 @@ static void prvRxTask(void *pvParameters)
// Rcvdstring, /* Data is read into this address. */
// portMAX_DELAY); /* Wait without a timeout for data. */

xil_printf("DEBUG: CPU 0 about to attempt rcv\r\n");
// xil_printf("DEBUG: CPU0 about to attempt rcv\r\n");
xil_printf("D\r\n");

size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBuffer, Rcvdstring, 32, portMAX_DELAY);
size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY);

xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd);
// xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd);
xil_printf("E\r\n");

if (bytes_rcvd == 0) {
xil_printf("CPU 0 failed to receive from ICC buffer\r\n");
// xil_printf("CPU0 failed to receive from ICC buffer\r\n");
xil_printf("F\r\n");
} else {
/* Print the received data. */
xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring);
// xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring);
xil_printf("G\r\n");
RxtaskCntr++;
}
}
Expand Down Expand Up @@ -341,7 +345,8 @@ static void vTimerCallback(TimerHandle_t pxTimer)
lTimerId = (long) pvTimerGetTimerID(pxTimer);

if (lTimerId != TIMER_ID) {
xil_printf("CPU0 - FreeRTOS Hello World Example FAILED");
// xil_printf("CPU0 - FreeRTOS Hello World Example FAILED");
xil_printf("H\r\n");
}

/* If the RxtaskCntr is updated every time the Rx task is called. The
Expand All @@ -351,10 +356,12 @@ static void vTimerCallback(TimerHandle_t pxTimer)
have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */
if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) {
message_status = 1;
xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n");
// xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n");
xil_printf("I\r\n");
} else {
message_status = 2;
xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n");
// xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n");
xil_printf("J\r\n");
}
}

Expand Down
38 changes: 23 additions & 15 deletions sdk/freertos_app_cpu1/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,14 @@ int main(void)

const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS);

xil_printf("CPU1 - Hello from FreeRTOS example main()!\r\n");

/* Create the two tasks. The Tx task is given a lower priority than the
Rx task, so the Rx task will leave the Blocked state and pre-empt the Tx
task as soon as the Tx task places an item in the queue. */
xTaskCreate(prvTxTask, /* The function that implements the task. */
(const char *) "CPU1_Tx", /* Text name for the task, provided to assist debugging only. */
configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */
NULL, /* The task parameter is not used, so set to NULL. */
tskIDLE_PRIORITY, /* The task runs at the idle priority. */
tskIDLE_PRIORITY,
&xTxTaskHandle);

xTaskCreate(prvRxTask, /* The function that implements the task. */
Expand Down Expand Up @@ -199,15 +197,18 @@ static void prvTxTask(void *pvParameters)
// HWstring, /* The address of the data being sent. */
// 0UL); /* The block time. */

xil_printf("DEBUG: CPU 1 about to attempt send\r\n");
// xil_printf("DEBUG: CPU1 about to attempt send\r\n");
xil_printf("a\r\n");

// Send a message to the other core
size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBuffer, HWstring, sizeof(HWstring), 0UL);
size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBufferHandle, HWstring, sizeof(HWstring), 0UL);

xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent);
// xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent);
xil_printf("b\r\n");

if (bytes_sent == 0) {
xil_printf("ERROR: CPU 1 failed to write to ICC buffer\r\n");
// xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n");
xil_printf("c\r\n");
}
}
}
Expand All @@ -229,17 +230,21 @@ static void prvRxTask(void *pvParameters)
// Rcvdstring, /* Data is read into this address. */
// portMAX_DELAY); /* Wait without a timeout for data. */

xil_printf("DEBUG: CPU 1 about to attempt rcv\r\n");
// xil_printf("DEBUG: CPU1 about to attempt rcv\r\n");
xil_printf("d\r\n");

size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBuffer, Rcvdstring, 32, portMAX_DELAY);
size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY);

xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer", bytes_rcvd);
// xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd);
xil_printf("e\r\n");

if (bytes_rcvd == 0) {
xil_printf("CPU 1 failed to receive from ICC buffer\r\n");
// xil_printf("CPU1 failed to receive from ICC buffer\r\n");
xil_printf("f\r\n");
} else {
/* Print the received data. */
xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring);
// xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring);
xil_printf("g\r\n");
RxtaskCntr++;
}
}
Expand All @@ -255,7 +260,8 @@ static void vTimerCallback(TimerHandle_t pxTimer)
lTimerId = (long) pvTimerGetTimerID(pxTimer);

if (lTimerId != TIMER_ID) {
xil_printf("CPU1 - FreeRTOS Hello World Example FAILED");
// xil_printf("CPU1 - FreeRTOS Hello World Example FAILED");
xil_printf("h\r\n");
}

/* If the RxtaskCntr is updated every time the Rx task is called. The
Expand All @@ -265,10 +271,12 @@ static void vTimerCallback(TimerHandle_t pxTimer)
have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */
if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) {
message_status = 1;
xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n");
// xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n");
xil_printf("i\r\n");
} else {
message_status = 2;
xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n");
// xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n");
xil_printf("j\r\n");
}
}

Expand Down
115 changes: 81 additions & 34 deletions sdk/shared/sys/icc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,72 @@
// CPUs, use "#if XPAR_CPU_ID == ?"
///////////////////////////////////////////////////////

void icc_init(uint32_t cpu_num)
void icc_init()
{
#if XPAR_CPU_ID == 0
// ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS
// CPU0 HANDLES INITIALIZING THE MESSAGE BUFFERS

// Wait for CPU1 to provide the function pointers to its callbacks ()
while (!ICC_getFunctionPointersReady)
;

// Use the getters once ready
void (*vCPU0to1ReceiveCallback)() = ICC_getCPU0to1ReceiveCallback;
// xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback);
void (*vCPU1to0SendCallback)() = ICC_getCPU1to0SendCallback;
// xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback);

/* Create two message buffers for inter-core communication that use the callback
* functions below as send and receive completed callback functions. */
xCPU0to1MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1,
ICC_CPU0to1_BufferSpaceAddr,
ICC_CPU0to1_BufferStructAddr,
vCPU0to1SendCallback,
vCPU0to1ReceiveCallback);

xCPU1to0MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1,
ICC_CPU1to0_BufferSpaceAddr,
ICC_CPU1to0_BufferStructAddr,
vCPU1to0SendCallback,
vCPU1to0ReceiveCallback);
xCPU0to1MessageBufferHandle = xMessageBufferCreateStaticWithCallback(
ICC_BUFFER_SIZE - 1,
ICC_CPU0to1BufferSpaceAddr,
ICC_CPU0to1BufferStructAddr,
vCPU0to1SendCallback, // Called by CPU0 after placing message in 0to1 buffer
vCPU0to1ReceiveCallback); // Called by CPU1 after removing message from 0to1 buffer

xCPU1to0MessageBufferHandle = xMessageBufferCreateStaticWithCallback(
ICC_BUFFER_SIZE - 1,
ICC_CPU1to0BufferSpaceAddr,
ICC_CPU1to0BufferStructAddr,
vCPU1to0SendCallback, // Called by CPU1 after placing message in 1to0 buffer
vCPU1to0ReceiveCallback); // Called by CPU0 after removing message from 1to0 buffer

ICC_setCPU0to1Handle(xCPU0to1MessageBufferHandle);
// xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle);
ICC_setCPU1to0Handle(xCPU1to0MessageBufferHandle);
// xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle);

ICC_setHandleComplete;
#elif XPAR_CPU_ID == 1
/* need to stall 10ms to "guarantee" that CPU1 does not get before CPU0 sets
* The APU freq is 666,666,687 Hz (per ps7_init.h), so a single NOP is 1/(666,666,687) or 1.5ns
* Therefore we need 6.66E6 NOPs to stall 10ms
*/

// Make CPU1's callback function pointers available to CPU0
ICC_setCPU1to0SendCallback(&vCPU1to0SendCallback);
// xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback);
ICC_setCPU0to1ReceiveCallback(&vCPU0to1ReceiveCallback);
// xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback);

ICC_setFunctionPointersReady;

// Wait for CPU0 to finish creating buffers and providing the handles
while (!ICC_getHandleComplete)
;

xCPU0to1MessageBufferHandle = ICC_getCPU0to1Handle;
// xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle);
xCPU1to0MessageBufferHandle = ICC_getCPU1to0Handle;
// xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle);
#endif
}

/* From FreeRTOS:
* Insert code into callback which is invoked when a message is written to the message buffer.
* This is useful when a message buffer is used to pass messages between
* cores on a multicore processor. In that scenario, this callback
* cores on a multi-core processor. In that scenario, this callback
* can be implemented to generate an interrupt in the other CPU core,
* and the interrupt's service routine can then use the
* xMessageBufferSendCompletedFromISR() API function to check, and if
Expand All @@ -46,46 +87,52 @@ void icc_init(uint32_t cpu_num)
* send to the 0 to 1 buffer, so in CPU 1 this callback doesn't need to DO ANYTHING except exist.
* - Patrick */

#if XPAR_CPU_ID == 0

void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer,
BaseType_t xIsInsideISR,
BaseType_t *const pxHigherPriorityTaskWoken)
{
#if XPAR_CPU_ID == 0
xil_printf("DEBUG: CPU 0 to 1 Send Callback reached\r\n");
// In CPU 0, this callback should send an interrupt to CPU 1's Rx task
XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID);
#endif
// xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n");
xil_printf("K\r\n");

// CPU 0 should send an interrupt to CPU1 to unblock its Rx task
int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID, XSCUGIC_SPI_CPU1_MASK);
}

void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer,
BaseType_t xIsInsideISR,
BaseType_t *const pxHigherPriorityTaskWoken)
{
#if XPAR_CPU_ID == 0
xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached\r\n");
// In CPU 0, this callback should send an interrupt to CPU 1's Tx task
XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID);
#endif
// xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n");
xil_printf("L\r\n");

// CPU0 should send an interrupt to CPU1 to unblock its Tx task (the buffer might have an open space now)
int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID, XSCUGIC_SPI_CPU1_MASK);
}

#elif XPAR_CPU_ID == 1

void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer,
BaseType_t xIsInsideISR,
BaseType_t *const pxHigherPriorityTaskWoken)
{
#if XPAR_CPU_ID == 1
xil_printf("DEBUG: CPU 1 to 0 Send Callback reached\r\n");
// In CPU 1, this callback should send an interrupt to CPU 0's Rx task
XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID);
#endif
// xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n");
xil_printf("k\r\n");

// CPU 1 should send an interrupt to CPU0 to unblock its Rx task
int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID, XSCUGIC_SPI_CPU0_MASK);
}

void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer,
BaseType_t xIsInsideISR,
BaseType_t *const pxHigherPriorityTaskWoken)
{
#if XPAR_CPU_ID == 1
xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached\r\n");
// In CPU 1, this callback should send an interrupt to CPU 0's Tx task
XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID);
#endif
// xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n");
xil_printf("l\r\n");

// CPU 1 should send an interrupt to CPU0 to unblock its Tx task (the buffer might have an open space)
int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID, XSCUGIC_SPI_CPU0_MASK);
}

#endif
Loading
Loading