Components and supplies
Arduino UNO
Project description
Code
ThreadHandlerDemo
c_cpp
1#include "ThreadHandler.h" 2 3int freeMemory(); 4 5//first we need to configure ThreadHandler 6 7//1ms driving interrupt 8SET_THREAD_HANDLER_TICK(1000) 9 10//using default interrupt timer 11THREAD_HANDLER(InterruptTimer::getInstance()) 12 13//next we need to create the threads 14 15// //this can be done using the createThread function with a lambda 16// Thread* thread1 = createThread(prio, period, offset, 17// []() 18// { 19// //code to run 20// }); 21// 22// //or with a function pointer 23// void run() 24// { 25// //code to run 26// } 27// 28// Thread* thread2 = createThread(prio, period, offset, run); 29 30//but using inheritance is slightly more memory efficient 31 32uint16_t numberOfCreatedThreads = 0; 33uint16_t minFreeMemory = -1; 34uint16_t priorityMaxTimingError[7] = {0}; 35 36class MyThread : public Thread 37{ 38public: 39 MyThread() : Thread( 40 //we want to spread out the threads over 7 41 //different priorities 42 numberOfCreatedThreads % 7, 43 //and we want 6ms period 44 6000, 45 //and to even out the CPU load we 46 //want the start time of the threads 47 //to be offset 48 1000 * (numberOfCreatedThreads / 12)) 49 { 50 numberOfCreatedThreads++; 51 } 52 53 void run() override 54 { 55 //since all threads will read and write to the monitoring variable 56 // we need to add a critical section to avoid racing conditions 57 58 //critical section 59 { 60 ThreadInterruptBlocker blocker; 61 62 //lets add some code for monitoring memory usage and timing errors 63 64 uint16_t mem = freeMemory(); 65 66 if (mem < minFreeMemory) 67 { 68 minFreeMemory = mem; 69 } 70 71 uint16_t timingError = getTimingError(); 72 73 uint16_t& maxTimingErrorForPrio = priorityMaxTimingError[getPriority()]; 74 75 if (timingError > maxTimingErrorForPrio) 76 { 77 maxTimingErrorForPrio = timingError; 78 } 79 } 80 81 } 82}; 83 84//max size thread array on 85// Arduino Uno: 86// 16MHz, 2KB SRAM (ATmega328P) 87MyThread threads[57]; 88 89//will you ever need 57 threads? 90//probably not... so lets try and 91//see how ThreadHandler perform with 92//just 7 threads 93//MyThread threads[7]; 94 95void printHeader(); 96 97void setup() 98{ 99 Serial.begin(9600); 100 101 //lets also add a nice header printout 102 printHeader(); 103 104 //to start thread execution we need to call the enableThreadExecution function 105 ThreadHandler::getInstance()->enableThreadExecution(); 106} 107 108void loop() 109{ 110 //next we need to print out the monitoring data 111 // with some nice formating 112 113 //we want to print every 500ms 114 delay(500); 115 116 Serial.print("| "); 117 118 for (auto& timingError : priorityMaxTimingError) 119 { 120 uint16_t timingErrorCopy; 121 122 //critical section 123 { 124 ThreadInterruptBlocker blocker; 125 126 timingErrorCopy = timingError; 127 timingError = 0; 128 } 129 130 Serial.print(timingErrorCopy); 131 Serial.print("us| "); 132 } 133 134 uint16_t minMemCopy; 135 136 //critical section 137 { 138 ThreadInterruptBlocker blocker; 139 140 minMemCopy = minFreeMemory; 141 minFreeMemory = -1; 142 } 143 144 Serial.print(minMemCopy); 145 Serial.print("b| "); 146 Serial.print(ThreadHandler::getInstance()->getCpuLoad()); 147 Serial.println("%|"); 148} 149 150//to minimize SRAM usage this function will only use 151//Serial.print(char). It is quite long so I will just 152//copy it in 153 154//SRAM memory optimized function to print header text: 155// 156// | Max absolute timing error for each priority | Free mem| 157// |------------------------------------------------| ______ 158// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | CPU| 159// 160#define p(c) Serial.print(c) 161#define pl(c) Serial.println(c) 162void printHeader() 163{ 164 p('|'); 165 p(' '); 166 p('M'); 167 p('a'); 168 p('x'); 169 p(' '); 170 p('a'); 171 p('b'); 172 p('s'); 173 p('o'); 174 p('l'); 175 p('u'); 176 p('t'); 177 p('e'); 178 p(' '); 179 p('t'); 180 p('i'); 181 p('m'); 182 p('i'); 183 p('n'); 184 p('g'); 185 p(' '); 186 p('e'); 187 p('r'); 188 p('r'); 189 p('o'); 190 p('r'); 191 p(' '); 192 p('f'); 193 p('o'); 194 p('r'); 195 p(' '); 196 p('e'); 197 p('a'); 198 p('c'); 199 p('h'); 200 p(' '); 201 p('p'); 202 p('r'); 203 p('i'); 204 p('o'); 205 p('r'); 206 p('i'); 207 p('t'); 208 p('y'); 209 p(' '); 210 p(' '); 211 p(' '); 212 p(' '); 213 p('|'); 214 p(' '); 215 p('F'); 216 p('r'); 217 p('e'); 218 p('e'); 219 p(' '); 220 p('m'); 221 p('e'); 222 p('m'); 223 pl('|'); 224 225 p('|'); 226 p('-'); 227 p('-'); 228 p('-'); 229 p('-'); 230 p('-'); 231 p('-'); 232 p('-'); 233 p('-'); 234 p('-'); 235 p('-'); 236 p('-'); 237 p('-'); 238 p('-'); 239 p('-'); 240 p('-'); 241 p('-'); 242 p('-'); 243 p('-'); 244 p('-'); 245 p('-'); 246 p('-'); 247 p('-'); 248 p('-'); 249 p('-'); 250 p('-'); 251 p('-'); 252 p('-'); 253 p('-'); 254 p('-'); 255 p('-'); 256 p('-'); 257 p('-'); 258 p('-'); 259 p('-'); 260 p('-'); 261 p('-'); 262 p('-'); 263 p('-'); 264 p('-'); 265 p('-'); 266 p('-'); 267 p('-'); 268 p('-'); 269 p('-'); 270 p('-'); 271 p('-'); 272 p('-'); 273 p('-'); 274 p('|'); 275 p(' '); 276 p(' '); 277 p(' '); 278 p(' '); 279 p('_'); 280 p('_'); 281 p('_'); 282 p('_'); 283 p('_'); 284 pl('_'); 285 286 p('|'); 287 p(' '); 288 p(' '); 289 p(' '); 290 p('0'); 291 p(' '); 292 p(' '); 293 p('|'); 294 p(' '); 295 p(' '); 296 p(' '); 297 p('1'); 298 p(' '); 299 p(' '); 300 p('|'); 301 p(' '); 302 p(' '); 303 p(' '); 304 p('2'); 305 p(' '); 306 p(' '); 307 p('|'); 308 p(' '); 309 p(' '); 310 p(' '); 311 p('3'); 312 p(' '); 313 p(' '); 314 p('|'); 315 p(' '); 316 p(' '); 317 p(' '); 318 p('4'); 319 p(' '); 320 p(' '); 321 p('|'); 322 p(' '); 323 p(' '); 324 p(' '); 325 p('5'); 326 p(' '); 327 p(' '); 328 p('|'); 329 p(' '); 330 p(' '); 331 p(' '); 332 p('6'); 333 p(' '); 334 p(' '); 335 p('|'); 336 p(' '); 337 p(' '); 338 p(' '); 339 p(' '); 340 p('|'); 341 p(' '); 342 p('C'); 343 p('P'); 344 p('U'); 345 pl('|'); 346} 347 348//freeMemory implementation 349 350#if !defined(__AVR__) 351 352#ifdef __arm__ 353// should use uinstd.h to define sbrk but Due causes a conflict 354extern "C" char* sbrk(int incr); 355#else // __ARM__ 356extern char *__brkval; 357#endif // __arm__ 358 359int freeMemory() { 360 char top; 361#ifdef __arm__ 362 return &top - reinterpret_cast<char*>(sbrk(0)); 363#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) 364 return &top - __brkval; 365#else // __arm__ 366 return __brkval ? &top - __brkval : &top - __malloc_heap_start; 367#endif // __arm__ 368} 369 370#else 371 372#if (ARDUINO >= 100) 373#include <Arduino.h> 374#else 375#include <WProgram.h> 376#endif 377 378extern unsigned int __heap_start; 379extern void *__brkval; 380 381/* 382 * The free list structure as maintained by the 383 * avr-libc memory allocation routines. 384 */ 385struct __freelist { 386 size_t sz; 387 struct __freelist *nx; 388}; 389 390/* The head of the free list structure */ 391extern struct __freelist *__flp; 392 393/* Calculates the size of the free list */ 394int freeListSize() { 395 struct __freelist* current; 396 int total = 0; 397 for (current = __flp; current; current = current->nx) { 398 total += 2; /* Add two bytes for the memory block's header */ 399 total += (int) current->sz; 400 } 401 return total; 402} 403 404int freeMemory() { 405 int free_memory; 406 if ((int)__brkval == 0) { 407 free_memory = ((int)&free_memory) - ((int)&__heap_start); 408 } else { 409 free_memory = ((int)&free_memory) - ((int)__brkval); 410 free_memory += freeListSize(); 411 } 412 return free_memory; 413} 414 415#endif 416
ThreadHandler
Library git repository
ThreadHandlerDemo
c_cpp
1#include "ThreadHandler.h" 2 3int freeMemory(); 4 5//first we 6 need to configure ThreadHandler 7 8//1ms driving interrupt 9SET_THREAD_HANDLER_TICK(1000) 10 11//using 12 default interrupt timer 13THREAD_HANDLER(InterruptTimer::getInstance()) 14 15//next 16 we need to create the threads 17 18// //this can be done using the createThread 19 function with a lambda 20// Thread* thread1 = createThread(prio, period, offset, 21// 22 []() 23// { 24// //code to run 25// }); 26// 27 28// //or with a function pointer 29// void run() 30// { 31// //code to 32 run 33// } 34// 35// Thread* thread2 = createThread(prio, period, offset, run); 36 37//but 38 using inheritance is slightly more memory efficient 39 40uint16_t numberOfCreatedThreads 41 = 0; 42uint16_t minFreeMemory = -1; 43uint16_t priorityMaxTimingError[7] = {0}; 44 45class 46 MyThread : public Thread 47{ 48public: 49 MyThread() : Thread( 50 //we 51 want to spread out the threads over 7 52 //different priorities 53 numberOfCreatedThreads 54 % 7, 55 //and we want 6ms period 56 6000, 57 //and to even 58 out the CPU load we 59 //want the start time of the threads 60 //to 61 be offset 62 1000 * (numberOfCreatedThreads / 12)) 63 { 64 numberOfCreatedThreads++; 65 66 } 67 68 void run() override 69 { 70 //since all threads will 71 read and write to the monitoring variable 72 // we need to add a critical 73 section to avoid racing conditions 74 75 //critical section 76 { 77 78 ThreadInterruptBlocker blocker; 79 80 //lets add some code 81 for monitoring memory usage and timing errors 82 83 uint16_t mem = 84 freeMemory(); 85 86 if (mem < minFreeMemory) 87 { 88 minFreeMemory 89 = mem; 90 } 91 92 uint16_t timingError = getTimingError(); 93 94 95 uint16_t& maxTimingErrorForPrio = priorityMaxTimingError[getPriority()]; 96 97 98 if (timingError > maxTimingErrorForPrio) 99 { 100 maxTimingErrorForPrio 101 = timingError; 102 } 103 } 104 105 } 106}; 107 108//max size 109 thread array on 110// Arduino Uno: 111// 16MHz, 2KB SRAM (ATmega328P) 112MyThread 113 threads[57]; 114 115//will you ever need 57 threads? 116//probably not... so lets 117 try and 118//see how ThreadHandler perform with 119//just 7 threads 120//MyThread 121 threads[7]; 122 123void printHeader(); 124 125void setup() 126{ 127 Serial.begin(9600); 128 129 130 //lets also add a nice header printout 131 printHeader(); 132 133 //to 134 start thread execution we need to call the enableThreadExecution function 135 ThreadHandler::getInstance()->enableThreadExecution(); 136} 137 138void 139 loop() 140{ 141 //next we need to print out the monitoring data 142 // with 143 some nice formating 144 145 //we want to print every 500ms 146 delay(500); 147 148 149 Serial.print("| "); 150 151 for (auto& timingError : priorityMaxTimingError) 152 153 { 154 uint16_t timingErrorCopy; 155 156 //critical section 157 158 { 159 ThreadInterruptBlocker blocker; 160 161 timingErrorCopy 162 = timingError; 163 timingError = 0; 164 } 165 166 Serial.print(timingErrorCopy); 167 168 Serial.print("us| "); 169 } 170 171 uint16_t minMemCopy; 172 173 174 //critical section 175 { 176 ThreadInterruptBlocker blocker; 177 178 179 minMemCopy = minFreeMemory; 180 minFreeMemory = -1; 181 } 182 183 184 Serial.print(minMemCopy); 185 Serial.print("b| "); 186 Serial.print(ThreadHandler::getInstance()->getCpuLoad()); 187 188 Serial.println("%|"); 189} 190 191//to minimize SRAM usage this function will 192 only use 193//Serial.print(char). It is quite long so I will just 194//copy it in 195 196//SRAM 197 memory optimized function to print header text: 198// 199// | Max absolute timing 200 error for each priority | Free mem| 201// |------------------------------------------------| 202 ______ 203// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | CPU| 204// 205#define 206 p(c) Serial.print(c) 207#define pl(c) Serial.println(c) 208void printHeader() 209{ 210 211 p('|'); 212 p(' '); 213 p('M'); 214 p('a'); 215 p('x'); 216 p(' 217 '); 218 p('a'); 219 p('b'); 220 p('s'); 221 p('o'); 222 p('l'); 223 224 p('u'); 225 p('t'); 226 p('e'); 227 p(' '); 228 p('t'); 229 p('i'); 230 231 p('m'); 232 p('i'); 233 p('n'); 234 p('g'); 235 p(' '); 236 p('e'); 237 238 p('r'); 239 p('r'); 240 p('o'); 241 p('r'); 242 p(' '); 243 p('f'); 244 245 p('o'); 246 p('r'); 247 p(' '); 248 p('e'); 249 p('a'); 250 p('c'); 251 252 p('h'); 253 p(' '); 254 p('p'); 255 p('r'); 256 p('i'); 257 p('o'); 258 259 p('r'); 260 p('i'); 261 p('t'); 262 p('y'); 263 p(' '); 264 p(' 265 '); 266 p(' '); 267 p(' '); 268 p('|'); 269 p(' '); 270 p('F'); 271 272 p('r'); 273 p('e'); 274 p('e'); 275 p(' '); 276 p('m'); 277 p('e'); 278 279 p('m'); 280 pl('|'); 281 282 p('|'); 283 p('-'); 284 p('-'); 285 286 p('-'); 287 p('-'); 288 p('-'); 289 p('-'); 290 p('-'); 291 p('-'); 292 293 p('-'); 294 p('-'); 295 p('-'); 296 p('-'); 297 p('-'); 298 p('-'); 299 300 p('-'); 301 p('-'); 302 p('-'); 303 p('-'); 304 p('-'); 305 p('-'); 306 307 p('-'); 308 p('-'); 309 p('-'); 310 p('-'); 311 p('-'); 312 p('-'); 313 314 p('-'); 315 p('-'); 316 p('-'); 317 p('-'); 318 p('-'); 319 p('-'); 320 321 p('-'); 322 p('-'); 323 p('-'); 324 p('-'); 325 p('-'); 326 p('-'); 327 328 p('-'); 329 p('-'); 330 p('-'); 331 p('-'); 332 p('-'); 333 p('-'); 334 335 p('-'); 336 p('-'); 337 p('-'); 338 p('-'); 339 p('|'); 340 p(' 341 '); 342 p(' '); 343 p(' '); 344 p(' '); 345 p('_'); 346 p('_'); 347 348 p('_'); 349 p('_'); 350 p('_'); 351 pl('_'); 352 353 p('|'); 354 355 p(' '); 356 p(' '); 357 p(' '); 358 p('0'); 359 p(' '); 360 p(' 361 '); 362 p('|'); 363 p(' '); 364 p(' '); 365 p(' '); 366 p('1'); 367 368 p(' '); 369 p(' '); 370 p('|'); 371 p(' '); 372 p(' '); 373 p(' 374 '); 375 p('2'); 376 p(' '); 377 p(' '); 378 p('|'); 379 p(' '); 380 381 p(' '); 382 p(' '); 383 p('3'); 384 p(' '); 385 p(' '); 386 p('|'); 387 388 p(' '); 389 p(' '); 390 p(' '); 391 p('4'); 392 p(' '); 393 p(' 394 '); 395 p('|'); 396 p(' '); 397 p(' '); 398 p(' '); 399 p('5'); 400 401 p(' '); 402 p(' '); 403 p('|'); 404 p(' '); 405 p(' '); 406 p(' 407 '); 408 p('6'); 409 p(' '); 410 p(' '); 411 p('|'); 412 p(' '); 413 414 p(' '); 415 p(' '); 416 p(' '); 417 p('|'); 418 p(' '); 419 p('C'); 420 421 p('P'); 422 p('U'); 423 pl('|'); 424} 425 426//freeMemory implementation 427 428#if 429 !defined(__AVR__) 430 431#ifdef __arm__ 432// should use uinstd.h to define sbrk 433 but Due causes a conflict 434extern "C" char* sbrk(int incr); 435#else // __ARM__ 436extern 437 char *__brkval; 438#endif // __arm__ 439 440int freeMemory() { 441 char top; 442#ifdef 443 __arm__ 444 return &top - reinterpret_cast<char*>(sbrk(0)); 445#elif defined(CORE_TEENSY) 446 || (ARDUINO > 103 && ARDUINO != 151) 447 return &top - __brkval; 448#else // __arm__ 449 450 return __brkval ? &top - __brkval : &top - __malloc_heap_start; 451#endif // 452 __arm__ 453} 454 455#else 456 457#if (ARDUINO >= 100) 458#include <Arduino.h> 459#else 460#include 461 <WProgram.h> 462#endif 463 464extern unsigned int __heap_start; 465extern void *__brkval; 466 467/* 468 469 * The free list structure as maintained by the 470 * avr-libc memory allocation 471 routines. 472 */ 473struct __freelist { 474 size_t sz; 475 struct __freelist *nx; 476}; 477 478/* 479 The head of the free list structure */ 480extern struct __freelist *__flp; 481 482/* 483 Calculates the size of the free list */ 484int freeListSize() { 485 struct __freelist* 486 current; 487 int total = 0; 488 for (current = __flp; current; current = current->nx) 489 { 490 total += 2; /* Add two bytes for the memory block's header */ 491 total 492 += (int) current->sz; 493 } 494 return total; 495} 496 497int freeMemory() { 498 499 int free_memory; 500 if ((int)__brkval == 0) { 501 free_memory = ((int)&free_memory) 502 - ((int)&__heap_start); 503 } else { 504 free_memory = ((int)&free_memory) - 505 ((int)__brkval); 506 free_memory += freeListSize(); 507 } 508 return free_memory; 509} 510 511#endif 512
Downloadable files
ThreadHandlerDemo connection example
Connection example for ThreadHandlerDemo
ThreadHandlerDemo connection example
ThreadHandlerDemo connection example
Connection example for ThreadHandlerDemo
ThreadHandlerDemo connection example
Comments
Only logged in users can leave comments