3232#include "uart.h"
3333
3434#define TASK_STACK_SIZE (512)
35+ #define ATOMIC_TASK_STACK_SIZE (256)
3536#define QUEUE_LENGTH (3)
3637#define NUM_ITEMS (5)
38+ #define ATOMIC_WORKER_TASKS (2U)
39+ #define ATOMIC_ITERATIONS_PER_WORKER (4000U)
3740
3841extern void freertos_risc_v_trap_handler (void );
3942
4043/* Shared resources */
4144static QueueHandle_t xDataQueue = NULL ;
4245static SemaphoreHandle_t xUartMutex = NULL ;
46+ static TaskHandle_t xConsumerTaskHandle = NULL ;
4347
4448/* Counters for demonstration */
4549static volatile uint32_t ulProducerCount = 0 ;
4650static volatile uint32_t ulConsumerCount = 0 ;
51+ static volatile uint32_t ulAtomicCounter = 0 ;
52+ static const uint32_t ulAtomicWorkerIds [ATOMIC_WORKER_TASKS ] = {1U , 2U };
4753
4854/*-----------------------------------------------------------*/
4955/* Safe UART output with mutex protection */
@@ -95,13 +101,50 @@ static void vProducerTask(void *pvParameters)
95101 vTaskDelete (NULL );
96102}
97103
104+ /*-----------------------------------------------------------*/
105+ /* Atomic increment helper (A extension) */
106+
107+ static inline void atomic_inc_amo (volatile uint32_t * target )
108+ {
109+ uint32_t one = 1U ;
110+ __asm volatile ("amoadd.w zero, %1, (%0)" : : "r" (target ), "r" (one ) : "memory" );
111+ }
112+
113+ /*-----------------------------------------------------------*/
114+ /* Atomic worker task - stress A extension under preemption */
115+
116+ static void vAtomicWorkerTask (void * pvParameters )
117+ {
118+ (void ) pvParameters ;
119+ uint32_t i ;
120+
121+ for (i = 0 ; i < ATOMIC_ITERATIONS_PER_WORKER ; i ++ ) {
122+ atomic_inc_amo (& ulAtomicCounter );
123+
124+ /* Force frequent interleaving across tasks. */
125+ if ((i & 0x3FU ) == 0U ) {
126+ taskYIELD ();
127+ }
128+ }
129+
130+ if (xConsumerTaskHandle != NULL ) {
131+ xTaskNotifyGive (xConsumerTaskHandle );
132+ }
133+
134+ vTaskDelete (NULL );
135+ }
136+
98137/*-----------------------------------------------------------*/
99138/* Consumer Task - receives data from queue */
100139
101140static void vConsumerTask (void * pvParameters )
102141{
103142 (void ) pvParameters ;
104143 uint32_t ulReceived ;
144+ uint32_t i ;
145+ BaseType_t xQueueOk ;
146+ BaseType_t xAtomicOk ;
147+ const uint32_t ulAtomicExpected = ATOMIC_WORKER_TASKS * ATOMIC_ITERATIONS_PER_WORKER ;
105148
106149 safe_print ("[Consumer] Task started (higher priority)\r\n" );
107150
@@ -121,19 +164,33 @@ static void vConsumerTask(void *pvParameters)
121164 }
122165 }
123166
167+ safe_print ("[Consumer] Waiting for atomic worker completion...\r\n" );
168+ for (i = 0 ; i < ATOMIC_WORKER_TASKS ; i ++ ) {
169+ (void ) ulTaskNotifyTake (pdTRUE , portMAX_DELAY );
170+ }
171+
172+ xQueueOk = (ulProducerCount == NUM_ITEMS ) && (ulConsumerCount == NUM_ITEMS );
173+ xAtomicOk = (ulAtomicCounter == ulAtomicExpected );
174+
124175 /* Print summary */
125176 if (xSemaphoreTake (xUartMutex , portMAX_DELAY ) == pdTRUE ) {
126177 uart_puts ("\r\n" );
127178 uart_puts ("=== Demo Complete ===\r\n" );
128- uart_puts ("Producer sent: " );
129- uart_putchar ('0' + ulProducerCount );
130- uart_puts (" items\r\n" );
131- uart_puts ("Consumer received: " );
132- uart_putchar ('0' + ulConsumerCount );
133- uart_puts (" items\r\n" );
134- uart_puts ("Queue + Mutex + Preemption: Working!\r\n" );
135- uart_puts ("\r\nPASS\r\n" );
136- uart_puts ("<<PASS>>\r\n" );
179+ uart_printf ("Producer sent: %lu items\r\n" , (unsigned long ) ulProducerCount );
180+ uart_printf ("Consumer received: %lu items\r\n" , (unsigned long ) ulConsumerCount );
181+ uart_printf ("Atomic counter: %lu/%lu\r\n" ,
182+ (unsigned long ) ulAtomicCounter ,
183+ (unsigned long ) ulAtomicExpected );
184+ uart_puts ("Queue + Mutex + Preemption + A-extension stress: " );
185+ if (xQueueOk == pdTRUE && xAtomicOk == pdTRUE ) {
186+ uart_puts ("Working!\r\n" );
187+ uart_puts ("\r\nPASS\r\n" );
188+ uart_puts ("<<PASS>>\r\n" );
189+ } else {
190+ uart_puts ("FAILED\r\n" );
191+ uart_puts ("\r\nFAIL\r\n" );
192+ uart_puts ("<<FAIL>>\r\n" );
193+ }
137194 xSemaphoreGive (xUartMutex );
138195 }
139196
@@ -198,14 +255,42 @@ int main(void)
198255 uart_puts ("[Main] Created Producer task (priority 1)\r\n" );
199256
200257 /* Create consumer task (priority 2 - higher, runs first when data available) */
201- if (xTaskCreate (vConsumerTask , "Consumer" , TASK_STACK_SIZE , NULL , tskIDLE_PRIORITY + 2 , NULL ) !=
202- pdPASS ) {
258+ if (xTaskCreate (vConsumerTask ,
259+ "Consumer" ,
260+ TASK_STACK_SIZE ,
261+ NULL ,
262+ tskIDLE_PRIORITY + 2 ,
263+ & xConsumerTaskHandle ) != pdPASS ) {
203264 uart_puts ("[ERROR] Consumer task creation failed\r\n" );
204265 for (;;)
205266 ;
206267 }
207268 uart_puts ("[Main] Created Consumer task (priority 2)\r\n" );
208269
270+ /* Create atomic stress workers (priority 1) */
271+ if (xTaskCreate (vAtomicWorkerTask ,
272+ "Atomic1" ,
273+ ATOMIC_TASK_STACK_SIZE ,
274+ (void * ) & ulAtomicWorkerIds [0 ],
275+ tskIDLE_PRIORITY + 1 ,
276+ NULL ) != pdPASS ) {
277+ uart_puts ("[ERROR] Atomic1 task creation failed\r\n" );
278+ for (;;)
279+ ;
280+ }
281+
282+ if (xTaskCreate (vAtomicWorkerTask ,
283+ "Atomic2" ,
284+ ATOMIC_TASK_STACK_SIZE ,
285+ (void * ) & ulAtomicWorkerIds [1 ],
286+ tskIDLE_PRIORITY + 1 ,
287+ NULL ) != pdPASS ) {
288+ uart_puts ("[ERROR] Atomic2 task creation failed\r\n" );
289+ for (;;)
290+ ;
291+ }
292+ uart_puts ("[Main] Created Atomic workers (priority 1)\r\n" );
293+
209294 uart_puts ("[Main] Starting scheduler...\r\n\r\n" );
210295
211296 /* Start the scheduler - never returns */
0 commit comments