├── .gitignore ├── README.md ├── examples ├── Benchmarking │ ├── Dhrystone │ │ ├── Dhrystone.ino │ │ └── dhry.h │ ├── MemoryAllocationStatistics │ │ └── MemoryAllocationStatistics.ino │ └── Whetstone │ │ ├── DoublePrecision │ │ └── DoublePrecision.ino │ │ └── SinglePrecision │ │ └── SinglePrecision.ino ├── Boards │ ├── STM32F746NG-DISCOVERY │ │ └── Ethernet_MQTT_Adafruit.io │ │ │ ├── Ethernet_MQTT_Adafruit.io.ino │ │ │ └── README.md │ └── STM32L475VG-DISCOVERY-IOT │ │ ├── BTLE_sensors_TimeOfFlight_demo │ │ └── BTLE_sensors_TimeOfFlight_demo.ino │ │ └── WiFi_MQTT_Adafruit.io │ │ ├── README.md │ │ └── WiFi_MQTT_Adafruit.io.ino ├── Communication │ └── MQTT │ │ ├── MQTTClient │ │ ├── Hello_stm32 │ │ │ └── Hello_stm32.ino │ │ └── README.md │ │ └── PubSubClient │ │ ├── README.md │ │ ├── mqtt_B-L475E-IOT01A │ │ └── mqtt_B-L475E-IOT01A.ino │ │ └── mqtt_STM32Ethernet │ │ └── mqtt_STM32Ethernet.ino ├── NonReg │ ├── Basics │ │ ├── STLTest │ │ │ ├── STLTest.ino │ │ │ ├── test_stl.c │ │ │ └── test_stl.h │ │ └── Tests_basic_functions │ │ │ ├── Test_IO.ino │ │ │ ├── Test_bytes.ino │ │ │ ├── Test_math.ino │ │ │ ├── Test_string.ino │ │ │ └── Tests_basic_functions.ino │ ├── BufferedEEPROM │ │ └── BufferedEEPROM.ino │ ├── CheckVariant │ │ ├── CheckVariant.ino │ │ ├── analogPinsTest.ino │ │ ├── checkIPInstanceTest.ino │ │ └── digitalPinsTest.ino │ ├── HardwareTimer │ │ └── HardwareTimer_OutputInput_test │ │ │ └── HardwareTimer_OutputInput_test.ino │ ├── PulseIn │ │ └── PulseIn.ino │ ├── RTC │ │ └── RTC_Tests │ │ │ ├── RTC_Config.ino │ │ │ ├── RTC_Tests.ino │ │ │ └── RTC_utils.ino │ ├── SPI_loop │ │ └── SPI_loop.ino │ └── SerialLoop │ │ └── SerialLoop.ino └── Peripherals │ ├── ADC │ └── Internal_channels │ │ └── Internal_channels.ino │ └── HardwareTimer │ ├── All-in-one_setPWM │ └── All-in-one_setPWM.ino │ ├── Frequency_Dutycycle_measurement │ └── Frequency_Dutycycle_measurement.ino │ ├── InputCapture │ └── InputCapture.ino │ ├── PWM_FullConfiguration │ └── PWM_FullConfiguration.ino │ ├── Timebase_callback │ └── Timebase_callback.ino │ └── Timebase_callback_with_parameter │ └── Timebase_callback_with_parameter.ino ├── img └── dashboard_adafruit.png ├── library.properties └── src └── STM32Examples.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STM32Examples 2 | Provides several examples for the Arduino core for STM32 MCUs. 3 | 4 | For the complete description of each example, please refer to the comments at the beginning of each .ino file 5 | or the README.md file in the sketch folder. 6 | 7 | ## Boards Examples 8 | * [STM32L475VG-DISCOVERY](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html): 9 | * BTLE_sensors_tof_demo: 10 | * get environmental data and send it via BlueTooth to your smartphone. 11 | * use Time of Flight sensor to detect gestures 12 | * WiFi_MQTT_Adafruit.io: 13 | * publish environmental data and send via WiFi using MQTT on https://io.adafruit.com 14 | * use HTS221 sensor to get temperature and humidity 15 | * [STM32F746G-DISCOVERY](http://www.st.com/en/evaluation-tools/32f746gdiscovery.html): 16 | * Ethernet_MQTT_Adafruit.io: 17 | * publish environmental data and send via Ethernet using MQTT on https://io.adafruit.com 18 | * use HTS221 sensor of [X-NUCLEO-IKS01A1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-sense-hw/x-nucleo-iks01a1.html) expansion board to get temperature and humidity 19 | 20 | Feel free to share your examples... 21 | -------------------------------------------------------------------------------- /examples/Benchmarking/Dhrystone/Dhrystone.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ************************************************************************* 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry_1.c (part 2 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * 15 | * Source: https://github.com/Keith-S-Thompson/dhrystone 16 | * 17 | ************************************************************************* 18 | */ 19 | #include "dhry.h" 20 | 21 | /* Global Variables: */ 22 | Rec_Pointer Ptr_Glob, 23 | Next_Ptr_Glob; 24 | int Int_Glob; 25 | Boolean Bool_Glob; 26 | char Ch_1_Glob, 27 | Ch_2_Glob; 28 | int Arr_1_Glob [25]; /* <-- changed from 50 */ 29 | int Arr_2_Glob [25] [25]; /* <-- changed from 50 */ 30 | 31 | char Reg_Define[] = "Register option selected."; 32 | 33 | #ifndef ROPT 34 | #define REG 35 | /* REG becomes defined as empty */ 36 | /* i.e. no register variables */ 37 | #else 38 | #define REG register 39 | #endif 40 | 41 | /* variables for time measurement: */ 42 | #define Too_Small_Time 2000000 43 | /* Measurements should last at least 2 seconds */ 44 | 45 | uint32_t Begin_Time, 46 | End_Time, 47 | User_Time; 48 | 49 | double Microseconds, 50 | Dhrystones_Per_Second, 51 | Vax_Mips; 52 | 53 | /* end of variables for time measurement */ 54 | 55 | void Proc_1( REG Rec_Pointer Ptr_Val_Par ); 56 | void Proc_2( One_Fifty * Int_Par_Ref ); 57 | void Proc_3( Rec_Pointer * Ptr_Ref_Par ); 58 | void Proc_4( void ); 59 | void Proc_5( void ); 60 | 61 | /* main program, corresponds to procedures */ 62 | /* Main and Proc_0 in the Ada version */ 63 | void setup() { 64 | 65 | One_Fifty Int_1_Loc; 66 | REG One_Fifty Int_2_Loc; 67 | One_Fifty Int_3_Loc; 68 | REG char Ch_Index; 69 | Enumeration Enum_Loc; 70 | Str_30 Str_1_Loc; 71 | Str_30 Str_2_Loc; 72 | REG int Run_Index; 73 | REG int Number_Of_Runs; 74 | 75 | /* Initializations */ 76 | Serial.begin(115200); 77 | while (!Serial) { 78 | ; // wait for serial port to connect 79 | } 80 | Serial.println("Dhrystone Benchmark, Version 2.1 (Language: C)"); 81 | 82 | Next_Ptr_Glob = (Rec_Pointer)malloc (sizeof (Rec_Type)); 83 | Ptr_Glob = (Rec_Pointer)malloc (sizeof (Rec_Type)); 84 | 85 | Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; 86 | Ptr_Glob->Discr = Ident_1; 87 | Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; 88 | Ptr_Glob->variant.var_1.Int_Comp = 40; 89 | strcpy (Ptr_Glob->variant.var_1.Str_Comp, 90 | "DHRYSTONE PROGRAM, SOME STRING"); 91 | strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); 92 | 93 | Arr_2_Glob [8][7] = 10; 94 | /* Was missing in published program. Without this statement, */ 95 | /* Arr_2_Glob [8][7] would have an undefined value. */ 96 | /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ 97 | /* overflow may occur for this array element. */ 98 | 99 | Number_Of_Runs = 300000; 100 | 101 | Serial.print("Execution starts, "); 102 | Serial.print(Number_Of_Runs); 103 | Serial.println(" runs through Dhrystone"); 104 | Serial.println(); 105 | 106 | /***************/ 107 | /* Start timer */ 108 | /***************/ 109 | 110 | Begin_Time = micros(); 111 | 112 | for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) 113 | { 114 | Proc_5(); 115 | Proc_4(); 116 | /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ 117 | Int_1_Loc = 2; 118 | Int_2_Loc = 3; 119 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); 120 | Enum_Loc = Ident_2; 121 | Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); 122 | /* Bool_Glob == 1 */ 123 | while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ 124 | { 125 | Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; 126 | /* Int_3_Loc == 7 */ 127 | Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); 128 | /* Int_3_Loc == 7 */ 129 | Int_1_Loc += 1; 130 | } /* while */ 131 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 132 | Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); 133 | /* Int_Glob == 5 */ 134 | Proc_1 (Ptr_Glob); 135 | for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) 136 | /* loop body executed twice */ 137 | { 138 | if (Enum_Loc == Func_1 (Ch_Index, 'C')) 139 | /* then, not executed */ 140 | { 141 | Proc_6 (Ident_1, &Enum_Loc); 142 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); 143 | Int_2_Loc = Run_Index; 144 | Int_Glob = Run_Index; 145 | } 146 | } 147 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 148 | Int_2_Loc = Int_2_Loc * Int_1_Loc; 149 | Int_1_Loc = Int_2_Loc / Int_3_Loc; 150 | Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; 151 | /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ 152 | Proc_2 (&Int_1_Loc); 153 | /* Int_1_Loc == 5 */ 154 | 155 | } /* loop "for Run_Index" */ 156 | 157 | /**************/ 158 | /* Stop timer */ 159 | /**************/ 160 | 161 | End_Time = micros(); 162 | 163 | Serial.println("Execution ends"); 164 | 165 | Serial.println(); 166 | Serial.println("Final values of the variables used in the benchmark:"); 167 | Serial.println(); 168 | Serial.print("Int_Glob: "); 169 | Serial.println(Int_Glob); 170 | Serial.println(" should be: 5"); 171 | Serial.print("Bool_Glob: "); 172 | Serial.println(Bool_Glob); 173 | Serial.println(" should be: 1"); 174 | Serial.print("Ch_1_Glob: "); 175 | Serial.println(Ch_1_Glob); 176 | Serial.println(" should be: A"); 177 | Serial.print("Ch_2_Glob: "); 178 | Serial.println(Ch_2_Glob); 179 | Serial.println(" should be: B"); 180 | Serial.print("Arr_1_Glob[8]: "); 181 | Serial.println(Arr_1_Glob[8]); 182 | Serial.println(" should be: 7"); 183 | Serial.print("Arr_2_Glob[8][7]: "); 184 | Serial.println(Arr_2_Glob[8][7]); 185 | Serial.println(" should be: Number_Of_Runs + 10"); 186 | Serial.println("Ptr_Glob->"); 187 | Serial.print(" Ptr_Comp: "); 188 | Serial.println((int) Ptr_Glob->Ptr_Comp); 189 | Serial.println(" should be: (implementation-dependent)"); 190 | Serial.print(" Discr: "); 191 | Serial.println(Ptr_Glob->Discr); 192 | Serial.println(" should be: 0"); 193 | Serial.print(" Enum_Comp: "); 194 | Serial.println(Ptr_Glob->variant.var_1.Enum_Comp); 195 | Serial.println(" should be: 2"); 196 | Serial.print(" Int_Comp: "); 197 | Serial.println(Ptr_Glob->variant.var_1.Int_Comp); 198 | Serial.println(" should be: 17"); 199 | Serial.print(" Str_Comp: "); 200 | Serial.println(Ptr_Glob->variant.var_1.Str_Comp); 201 | Serial.println(" should be: DHRYSTONE PROGRAM, SOME STRING"); 202 | Serial.println("Next_Ptr_Glob->"); 203 | Serial.print(" Ptr_Comp: "); 204 | Serial.println((int) Next_Ptr_Glob->Ptr_Comp); 205 | Serial.println(" should be: (implementation-dependent), same as above"); 206 | Serial.print(" Discr: "); 207 | Serial.println(Next_Ptr_Glob->Discr); 208 | Serial.println(" should be: 0"); 209 | Serial.print(" Enum_Comp: "); 210 | Serial.println(Next_Ptr_Glob->variant.var_1.Enum_Comp); 211 | Serial.println(" should be: 1"); 212 | Serial.print(" Int_Comp: "); 213 | Serial.println(Next_Ptr_Glob->variant.var_1.Int_Comp); 214 | Serial.println(" should be: 18"); 215 | Serial.print(" Str_Comp: "); 216 | Serial.println(Next_Ptr_Glob->variant.var_1.Str_Comp); 217 | Serial.println(" should be: DHRYSTONE PROGRAM, SOME STRING"); 218 | Serial.print("Int_1_Loc: "); 219 | Serial.println(Int_1_Loc); 220 | Serial.println(" should be: 5"); 221 | Serial.print("Int_2_Loc: "); 222 | Serial.println(Int_2_Loc); 223 | Serial.println(" should be: 13"); 224 | Serial.print("Int_3_Loc: "); 225 | Serial.println(Int_3_Loc); 226 | Serial.println(" should be: 7"); 227 | Serial.print("Enum_Loc: "); 228 | Serial.println(Enum_Loc); 229 | Serial.println(" should be: 1"); 230 | Serial.print("Str_1_Loc: "); 231 | Serial.println(Str_1_Loc); 232 | Serial.println(" should be: DHRYSTONE PROGRAM, 1'ST STRING"); 233 | Serial.print("Str_2_Loc: "); 234 | Serial.println(Str_2_Loc); 235 | Serial.println(" should be: DHRYSTONE PROGRAM, 2'ND STRING"); 236 | Serial.println(""); 237 | 238 | User_Time = End_Time - Begin_Time; 239 | 240 | if (User_Time < Too_Small_Time) 241 | { 242 | Serial.println("Measured time too small to obtain meaningful results"); 243 | Serial.println("Please increase number of runs"); 244 | Serial.println(); 245 | } 246 | else 247 | { 248 | Microseconds = (double) User_Time / (double) Number_Of_Runs; 249 | Dhrystones_Per_Second = (double) Number_Of_Runs / ((double)User_Time/1000000.0); 250 | Vax_Mips = Dhrystones_Per_Second / 1757.0; 251 | 252 | #ifdef ROPT 253 | Serial.println("Register option selected? YES"); 254 | #else 255 | Serial.println("Register option selected? NO"); 256 | strcpy(Reg_Define, "Register option not selected."); 257 | #endif 258 | 259 | Serial.print("Microseconds for one run through Dhrystone: "); 260 | Serial.println(Microseconds); 261 | Serial.print("Dhrystones per Second: "); 262 | Serial.println(Dhrystones_Per_Second); 263 | Serial.print("VAX MIPS rating = "); 264 | Serial.println(Vax_Mips); 265 | } 266 | } 267 | 268 | void loop() { 269 | } 270 | 271 | void Proc_1( REG Rec_Pointer Ptr_Val_Par ) 272 | /******************/ 273 | /* executed once */ 274 | { 275 | REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; 276 | /* == Ptr_Glob_Next */ 277 | /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ 278 | /* corresponds to "rename" in Ada, "with" in Pascal */ 279 | 280 | structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 281 | Ptr_Val_Par->variant.var_1.Int_Comp = 5; 282 | Next_Record->variant.var_1.Int_Comp 283 | = Ptr_Val_Par->variant.var_1.Int_Comp; 284 | Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; 285 | Proc_3 (&Next_Record->Ptr_Comp); 286 | /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 287 | == Ptr_Glob->Ptr_Comp */ 288 | if (Next_Record->Discr == Ident_1) 289 | /* then, executed */ 290 | { 291 | Next_Record->variant.var_1.Int_Comp = 6; 292 | Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 293 | &Next_Record->variant.var_1.Enum_Comp); 294 | Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; 295 | Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 296 | &Next_Record->variant.var_1.Int_Comp); 297 | } 298 | else /* not executed */ 299 | structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); 300 | } /* Proc_1 */ 301 | 302 | 303 | void Proc_2( One_Fifty * Int_Par_Ref ) 304 | /******************/ 305 | /* executed once */ 306 | /* *Int_Par_Ref == 1, becomes 4 */ 307 | { 308 | One_Fifty Int_Loc; 309 | Enumeration Enum_Loc; 310 | 311 | Int_Loc = *Int_Par_Ref + 10; 312 | do /* executed once */ 313 | if (Ch_1_Glob == 'A') 314 | /* then, executed */ 315 | { 316 | Int_Loc -= 1; 317 | *Int_Par_Ref = Int_Loc - Int_Glob; 318 | Enum_Loc = Ident_1; 319 | } /* if */ 320 | while (Enum_Loc != Ident_1); /* true */ 321 | } /* Proc_2 */ 322 | 323 | 324 | void Proc_3( Rec_Pointer * Ptr_Ref_Par ) 325 | /******************/ 326 | /* executed once */ 327 | /* Ptr_Ref_Par becomes Ptr_Glob */ 328 | { 329 | if (Ptr_Glob != Null) 330 | /* then, executed */ 331 | *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; 332 | Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); 333 | } /* Proc_3 */ 334 | 335 | 336 | void Proc_4( void ) /* without parameters */ 337 | /*******/ 338 | /* executed once */ 339 | { 340 | Boolean Bool_Loc; 341 | 342 | Bool_Loc = Ch_1_Glob == 'A'; 343 | Bool_Glob = Bool_Loc | Bool_Glob; 344 | Ch_2_Glob = 'B'; 345 | } /* Proc_4 */ 346 | 347 | 348 | void Proc_5( void ) /* without parameters */ 349 | /*******/ 350 | /* executed once */ 351 | { 352 | Ch_1_Glob = 'A'; 353 | Bool_Glob = false; 354 | } /* Proc_5 */ 355 | 356 | 357 | /* Procedure for the assignment of structures, */ 358 | /* if the C compiler doesn't support this feature */ 359 | #ifdef NOSTRUCTASSIGN 360 | memcpy (d, s, l) 361 | register char *d; 362 | register char *s; 363 | register int l; 364 | { 365 | while (l--) *d++ = *s++; 366 | } 367 | #endif 368 | 369 | /* 370 | ************************************************************************* 371 | * 372 | * "DHRYSTONE" Benchmark Program 373 | * ----------------------------- 374 | * 375 | * Version: C, Version 2.1 376 | * 377 | * File: dhry_2.c (part 3 of 3) 378 | * 379 | * Date: May 25, 1988 380 | * 381 | * Author: Reinhold P. Weicker 382 | * 383 | ************************************************************************* 384 | */ 385 | 386 | 387 | Boolean Func_3( Enumeration Enum_Par_Val ); 388 | 389 | void Proc_6( Enumeration Enum_Val_Par, Enumeration * Enum_Ref_Par ) 390 | /*********************************/ 391 | /* executed once */ 392 | /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ 393 | { 394 | *Enum_Ref_Par = Enum_Val_Par; 395 | if (! Func_3 (Enum_Val_Par)) 396 | /* then, not executed */ 397 | *Enum_Ref_Par = Ident_4; 398 | switch (Enum_Val_Par) 399 | { 400 | case Ident_1: 401 | *Enum_Ref_Par = Ident_1; 402 | break; 403 | case Ident_2: 404 | if (Int_Glob > 100) 405 | /* then */ 406 | *Enum_Ref_Par = Ident_1; 407 | else *Enum_Ref_Par = Ident_4; 408 | break; 409 | case Ident_3: /* executed */ 410 | *Enum_Ref_Par = Ident_2; 411 | break; 412 | case Ident_4: break; 413 | case Ident_5: 414 | *Enum_Ref_Par = Ident_3; 415 | break; 416 | } /* switch */ 417 | } /* Proc_6 */ 418 | 419 | 420 | void Proc_7( One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, 421 | One_Fifty * Int_Par_Ref ) 422 | /**********************************************/ 423 | /* executed three times */ 424 | /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ 425 | /* Int_Par_Ref becomes 7 */ 426 | /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ 427 | /* Int_Par_Ref becomes 17 */ 428 | /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ 429 | /* Int_Par_Ref becomes 18 */ 430 | { 431 | One_Fifty Int_Loc; 432 | 433 | Int_Loc = Int_1_Par_Val + 2; 434 | *Int_Par_Ref = Int_2_Par_Val + Int_Loc; 435 | } /* Proc_7 */ 436 | 437 | 438 | void Proc_8( Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref, 439 | int Int_1_Par_Val, int Int_2_Par_Val ) 440 | /*********************************************************************/ 441 | /* executed once */ 442 | /* Int_Par_Val_1 == 3 */ 443 | /* Int_Par_Val_2 == 7 */ 444 | { 445 | REG One_Fifty Int_Index; 446 | REG One_Fifty Int_Loc; 447 | 448 | Int_Loc = Int_1_Par_Val + 5; 449 | Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; 450 | Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; 451 | Arr_1_Par_Ref [Int_Loc+15] = Int_Loc; 452 | for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) 453 | Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; 454 | Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; 455 | Arr_2_Par_Ref [Int_Loc+10] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; 456 | Int_Glob = 5; 457 | } /* Proc_8 */ 458 | 459 | 460 | Enumeration Func_1 ( Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val ) 461 | /*************************************************/ 462 | /* executed three times */ 463 | /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ 464 | /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ 465 | /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ 466 | { 467 | Capital_Letter Ch_1_Loc; 468 | Capital_Letter Ch_2_Loc; 469 | 470 | Ch_1_Loc = Ch_1_Par_Val; 471 | Ch_2_Loc = Ch_1_Loc; 472 | if (Ch_2_Loc != Ch_2_Par_Val) 473 | /* then, executed */ 474 | return (Ident_1); 475 | else /* not executed */ 476 | { 477 | Ch_1_Glob = Ch_1_Loc; 478 | return (Ident_2); 479 | } 480 | } /* Func_1 */ 481 | 482 | 483 | Boolean Func_2( Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref ) 484 | /*************************************************/ 485 | /* executed once */ 486 | /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ 487 | /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ 488 | { 489 | REG One_Thirty Int_Loc; 490 | Capital_Letter Ch_Loc; 491 | 492 | Int_Loc = 2; 493 | while (Int_Loc <= 2) /* loop body executed once */ 494 | if (Func_1 (Str_1_Par_Ref[Int_Loc], 495 | Str_2_Par_Ref[Int_Loc+1]) == Ident_1) 496 | /* then, executed */ 497 | { 498 | Ch_Loc = 'A'; 499 | Int_Loc += 1; 500 | } /* if, while */ 501 | if (Ch_Loc >= 'W' && Ch_Loc < 'Z') 502 | /* then, not executed */ 503 | Int_Loc = 7; 504 | if (Ch_Loc == 'R') 505 | /* then, not executed */ 506 | return (true); 507 | else /* executed */ 508 | { 509 | if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) 510 | /* then, not executed */ 511 | { 512 | Int_Loc += 7; 513 | Int_Glob = Int_Loc; 514 | return (true); 515 | } 516 | else /* executed */ 517 | return (false); 518 | } /* if Ch_Loc */ 519 | } /* Func_2 */ 520 | 521 | 522 | Boolean Func_3( Enumeration Enum_Par_Val ) 523 | /***************************/ 524 | /* executed once */ 525 | /* Enum_Par_Val == Ident_3 */ 526 | { 527 | Enumeration Enum_Loc; 528 | 529 | Enum_Loc = Enum_Par_Val; 530 | if (Enum_Loc == Ident_3) 531 | /* then, executed */ 532 | return (true); 533 | else /* not executed */ 534 | return (false); 535 | } /* Func_3 */ 536 | 537 | -------------------------------------------------------------------------------- /examples/Benchmarking/Dhrystone/dhry.h: -------------------------------------------------------------------------------- 1 | /* 2 | ************************************************************************* 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry.h (part 1 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * Siemens Nixdorf Inf. Syst. 15 | * STM OS 32 16 | * Otto-Hahn-Ring 6 17 | * W-8000 Muenchen 83 18 | * Germany 19 | * Phone: [+49]-89-636-42436 20 | * (8-17 Central European Time) 21 | * UUCP: weicker@ztivax.uucp@unido.uucp 22 | * Internet: weicker@ztivax.siemens.com 23 | * 24 | * Original Version (in Ada) published in 25 | * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), 26 | * pp. 1013 - 1030, together with the statistics 27 | * on which the distribution of statements etc. is based. 28 | * 29 | * In this C version, the following C library functions are 30 | * used: 31 | * - strcpy, strcmp (inside the measurement loop) 32 | * - printf, scanf (outside the measurement loop) 33 | * 34 | * Collection of Results: 35 | * Reinhold Weicker (address see above) and 36 | * 37 | * Rick Richardson 38 | * PC Research. Inc. 39 | * 94 Apple Orchard Drive 40 | * Tinton Falls, NJ 07724 41 | * Phone: (201) 834-1378 (9-17 EST) 42 | * UUCP: ...!uunet!pcrat!rick 43 | * 44 | * Please send results to Rick Richardson and/or Reinhold Weicker. 45 | * Complete information should be given on hardware and software 46 | * used. Hardware information includes: Machine type, CPU, type and 47 | * size of caches; for microprocessors: clock frequency, memory speed 48 | * (number of wait states). Software information includes: Compiler 49 | * (and runtime library) manufacturer and version, compilation 50 | * switches, OS version. The Operating System version may give an 51 | * indication about the compiler; Dhrystone itself performs no OS 52 | * calls in the measurement loop. 53 | * 54 | * The complete output generated by the program should be mailed 55 | * such that at least some checks for correctness can be made. 56 | * 57 | ************************************************************************* 58 | * 59 | * History: This version C/2.1 has been made for two reasons: 60 | * 61 | * 1) There is an obvious need for a common C version of 62 | * Dhrystone, since C is at present the most popular system 63 | * programming language for the class of processors 64 | * (microcomputers, minicomputers) where Dhrystone is used 65 | * most. There should be, as far as possible, only one C 66 | * version of Dhrystone such that results can be compared 67 | * without restrictions. In the past, the C versions 68 | * distributed by Rick Richardson (Version 1.1) and by 69 | * Reinhold Weicker had small (though not significant) 70 | * differences. 71 | * 72 | * 2) As far as it is possible without changes to the 73 | * Dhrystone statistics, optimizing compilers should be 74 | * prevented from removing significant statements. 75 | * 76 | * This C version has been developed in cooperation with 77 | * Rick Richardson (Tinton Falls, NJ), it incorporates many 78 | * ideas from the "Version 1.1" distributed previously by 79 | * him over the UNIX network Usenet. 80 | * I also thank Chaim Benedelac (National Semiconductor), 81 | * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), 82 | * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) 83 | * for their help with comments on earlier versions of the 84 | * benchmark. 85 | * 86 | * Changes: In the initialization part, this version follows mostly 87 | * Rick Richardson's version distributed via Usenet, not the 88 | * version distributed earlier via floppy disk by Reinhold 89 | * Weicker. As a concession to older compilers, names have 90 | * been made unique within the first 8 characters. Inside the 91 | * measurement loop, this version follows the version 92 | * previously distributed by Reinhold Weicker. 93 | * 94 | * At several places in the benchmark, code has been added, 95 | * but within the measurement loop only in branches that 96 | * are not executed. The intention is that optimizing 97 | * compilers should be prevented from moving code out of the 98 | * measurement loop, or from removing code altogether. Since 99 | * the statements that are executed within the measurement 100 | * loop have NOT been changed, the numbers defining the 101 | * "Dhrystone distribution" (distribution of statements, 102 | * operand types and locality) still hold. Except for 103 | * sophisticated optimizing compilers, execution times for 104 | * this version should be the same as for previous versions. 105 | * 106 | * Since it has proven difficult to subtract the time for the 107 | * measurement loop overhead in a correct way, the loop check 108 | * has been made a part of the benchmark. This does have 109 | * an impact - though a very minor one - on the distribution 110 | * statistics which have been updated for this version. 111 | * 112 | * All changes within the measurement loop are described 113 | * and discussed in the companion paper "Rationale for 114 | * Dhrystone version 2". 115 | * 116 | * Because of the self-imposed limitation that the order and 117 | * distribution of the executed statements should not be 118 | * changed, there are still cases where optimizing compilers 119 | * may not generate code for some statements. To a certain 120 | * degree, this is unavoidable for small synthetic 121 | * benchmarks. Users of the benchmark are advised to check 122 | * code listings whether code is generated for all statements 123 | * of Dhrystone. 124 | * 125 | * Version 2.1 is identical to version 2.0 distributed via 126 | * the UNIX network Usenet in March 1988 except that it 127 | * corrects some minor deficiencies that were found by users 128 | * of version 2.0. The only change within the measurement 129 | * loop is that a non-executed "else" part was added to the 130 | * "if" statement in Func_3, and a non-executed "else" part 131 | * removed from Proc_3. 132 | * 133 | ************************************************************************* 134 | * 135 | * Defines: The following "Defines" are possible: 136 | * -DROPT (default: Not defined) 137 | * As an approximation to what an average C 138 | * programmer might do, the "register" storage class 139 | * is applied (if enabled by -DROPT) 140 | * - for local variables, if they are used 141 | * (dynamically) five or more times 142 | * - for parameters if they are used (dynamically) 143 | * six or more times 144 | * Note that an optimal "register" strategy is 145 | * compiler-dependent, and that "register" 146 | * declarations do not necessarily lead to faster 147 | * execution. 148 | * -DNOSTRUCTASSIGN (default: Not defined) 149 | * Define if the C compiler does not support 150 | * assignment of structures. 151 | * -DNOENUMS (default: Not defined) 152 | * Define if the C compiler does not support 153 | * enumeration types. 154 | * 155 | ************************************************************************* 156 | * 157 | * Compilation model and measurement (IMPORTANT): 158 | * 159 | * This C version of Dhrystone consists of three files: 160 | * - dhry.h (this file, containing global definitions and comments) 161 | * - dhry_1.c (containing the code corresponding to Ada package Pack_1) 162 | * - dhry_2.c (containing the code corresponding to Ada package Pack_2) 163 | * 164 | * The following "ground rules" apply for measurements: 165 | * - Separate compilation 166 | * - No procedure merging 167 | * - Otherwise, compiler optimizations are allowed but should be 168 | * indicated 169 | * - Default results are those without register declarations 170 | * See the companion paper "Rationale for Dhrystone Version 2" for a more 171 | * detailed discussion of these ground rules. 172 | * 173 | * For 16-Bit processors (e.g. 80186, 80286), times for all compilation 174 | * models ("small", "medium", "large" etc.) should be given if possible, 175 | * together with a definition of these models for the compiler system 176 | * used. 177 | * 178 | ************************************************************************* 179 | * 180 | * Dhrystone (C version) statistics: 181 | * 182 | * [Comment from the first distribution, updated for version 2. 183 | * Note that because of language differences, the numbers are slightly 184 | * different from the Ada version.] 185 | * 186 | * The following program contains statements of a high level programming 187 | * language (here: C) in a distribution considered representative: 188 | * 189 | * assignments 52 (51.0 %) 190 | * control statements 33 (32.4 %) 191 | * procedure, function calls 17 (16.7 %) 192 | * 193 | * 103 statements are dynamically executed. The program is balanced with 194 | * respect to the three aspects: 195 | * 196 | * - statement type 197 | * - operand type 198 | * - operand locality 199 | * operand global, local, parameter, or constant. 200 | * 201 | * The combination of these three aspects is balanced only approximately. 202 | * 203 | * 1. Statement Type: 204 | * ----------------- number 205 | * 206 | * V1 = V2 9 207 | * (incl. V1 = F(..) 208 | * V = Constant 12 209 | * Assignment, 7 210 | * with array element 211 | * Assignment, 6 212 | * with record component 213 | * -- 214 | * 34 34 215 | * 216 | * X = Y +|-|"&&"|"|" Z 5 217 | * X = Y +|-|"==" Constant 6 218 | * X = X +|- 1 3 219 | * X = Y *|/ Z 2 220 | * X = Expression, 1 221 | * two operators 222 | * X = Expression, 1 223 | * three operators 224 | * -- 225 | * 18 18 226 | * 227 | * if .... 14 228 | * with "else" 7 229 | * without "else" 7 230 | * executed 3 231 | * not executed 4 232 | * for ... 7 | counted every time 233 | * while ... 4 | the loop condition 234 | * do ... while 1 | is evaluated 235 | * switch ... 1 236 | * break 1 237 | * declaration with 1 238 | * initialization 239 | * -- 240 | * 34 34 241 | * 242 | * P (...) procedure call 11 243 | * user procedure 10 244 | * library procedure 1 245 | * X = F (...) 246 | * function call 6 247 | * user function 5 248 | * library function 1 249 | * -- 250 | * 17 17 251 | * --- 252 | * 103 253 | * 254 | * The average number of parameters in procedure or function calls 255 | * is 1.82 (not counting the function values as implicit parameters). 256 | * 257 | * 258 | * 2. Operators 259 | * ------------ 260 | * number approximate 261 | * percentage 262 | * 263 | * Arithmetic 32 50.8 264 | * 265 | * + 21 33.3 266 | * - 7 11.1 267 | * * 3 4.8 268 | * / (int div) 1 1.6 269 | * 270 | * Comparison 27 42.8 271 | * 272 | * == 9 14.3 273 | * /= 4 6.3 274 | * > 1 1.6 275 | * < 3 4.8 276 | * >= 1 1.6 277 | * <= 9 14.3 278 | * 279 | * Logic 4 6.3 280 | * 281 | * && (AND-THEN) 1 1.6 282 | * | (OR) 1 1.6 283 | * ! (NOT) 2 3.2 284 | * 285 | * -- ----- 286 | * 63 100.1 287 | * 288 | * 289 | * 3. Operand Type (counted once per operand reference): 290 | * --------------- 291 | * number approximate 292 | * percentage 293 | * 294 | * Integer 175 72.3 % 295 | * Character 45 18.6 % 296 | * Pointer 12 5.0 % 297 | * String30 6 2.5 % 298 | * Array 2 0.8 % 299 | * Record 2 0.8 % 300 | * --- ------- 301 | * 242 100.0 % 302 | * 303 | * When there is an access path leading to the final operand (e.g. a 304 | * record component), only the final data type on the access path is 305 | * counted. 306 | * 307 | * 308 | * 4. Operand Locality: 309 | * ------------------- 310 | * number approximate 311 | * percentage 312 | * 313 | * local variable 114 47.1 % 314 | * global variable 22 9.1 % 315 | * parameter 45 18.6 % 316 | * value 23 9.5 % 317 | * reference 22 9.1 % 318 | * function result 6 2.5 % 319 | * constant 55 22.7 % 320 | * --- ------- 321 | * 242 100.0 % 322 | * 323 | * 324 | * The program does not compute anything meaningful, but it is 325 | * syntactically and semantically correct. All variables have a value 326 | * assigned to them before they are used as a source operand. 327 | * 328 | * There has been no explicit effort to account for the effects of a 329 | * cache, or to balance the use of long or short displacements for code 330 | * or data. 331 | * 332 | ************************************************************************* 333 | */ 334 | 335 | /* Compiler and system dependent definitions: */ 336 | 337 | #define Mic_secs_Per_Second 1000000.0 338 | /* Berkeley UNIX C returns process times in seconds/HZ */ 339 | 340 | #ifdef NOSTRUCTASSIGN 341 | #define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) 342 | #else 343 | #define structassign(d, s) d = s 344 | #endif 345 | 346 | #ifdef NOENUM 347 | #define Ident_1 0 348 | #define Ident_2 1 349 | #define Ident_3 2 350 | #define Ident_4 3 351 | #define Ident_5 4 352 | typedef int Enumeration; 353 | #else 354 | typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} 355 | Enumeration; 356 | #endif 357 | /* for boolean and enumeration types in Ada, Pascal */ 358 | 359 | /* General definitions: */ 360 | 361 | 362 | #define Null 0 363 | /* Value of a Null pointer */ 364 | #define true 1 365 | #define false 0 366 | 367 | typedef int One_Thirty; 368 | typedef int One_Fifty; 369 | typedef char Capital_Letter; 370 | typedef int Boolean; 371 | typedef char Str_30 [31]; 372 | typedef int Arr_1_Dim [25]; /* <-- changed from 50 */ 373 | typedef int Arr_2_Dim [25] [25]; /* <-- changed from 50 */ 374 | 375 | typedef struct record 376 | { 377 | struct record *Ptr_Comp; 378 | Enumeration Discr; 379 | union { 380 | struct { 381 | Enumeration Enum_Comp; 382 | int Int_Comp; 383 | char Str_Comp [31]; 384 | } var_1; 385 | struct { 386 | Enumeration E_Comp_2; 387 | char Str_2_Comp [31]; 388 | } var_2; 389 | struct { 390 | char Ch_1_Comp; 391 | char Ch_2_Comp; 392 | } var_3; 393 | } variant; 394 | } Rec_Type, *Rec_Pointer; 395 | 396 | /* Prototypes of function defined in dhry21b.c and called from dhry21a.c. 397 | */ 398 | void Proc_6( Enumeration Enum_Val_Par, Enumeration * Enum_Ref_Par ); 399 | void Proc_7( One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, 400 | One_Fifty * Int_Par_Ref ); 401 | void Proc_8( Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref, 402 | int Int_1_Par_Val, int Int_2_Par_Val ); 403 | Enumeration Func_1( Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val ); 404 | Boolean Func_2( Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref ); 405 | 406 | 407 | -------------------------------------------------------------------------------- /examples/Benchmarking/MemoryAllocationStatistics/MemoryAllocationStatistics.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch employs mallinfo() to retrieve memory allocation 3 | statistics before and after allocating and freeing blocks of 4 | memory. The statistics are displayed on Serial. 5 | 6 | Creation 14 Feb 2018 7 | by Frederic Pillon 8 | 9 | This example code is in the public domain. 10 | 11 | Based on example from: 12 | http://man7.org/linux/man-pages/man3/mallinfo.3.html 13 | */ 14 | #include 15 | 16 | extern "C" char *sbrk(int i); 17 | /* Use linker definition */ 18 | extern char _end; 19 | extern char _sdata; 20 | extern char _estack; 21 | extern char _Min_Stack_Size; 22 | 23 | static char *ramstart = &_sdata; 24 | static char *ramend = &_estack; 25 | static char *minSP = (char*)(ramend - &_Min_Stack_Size); 26 | 27 | #define NUM_BLOCKS 100 28 | #define BLOCK_SIZE 4 29 | 30 | void display_mallinfo(void) 31 | { 32 | char *heapend = (char*)sbrk(0); 33 | char * stack_ptr = (char*)__get_MSP(); 34 | struct mallinfo mi = mallinfo(); 35 | 36 | Serial.print("Total non-mmapped bytes (arena): "); 37 | Serial.println(mi.arena); 38 | Serial.print("# of free chunks (ordblks): "); 39 | Serial.println(mi.ordblks); 40 | Serial.print("# of free fastbin blocks (smblks): "); 41 | Serial.println(mi.smblks); 42 | Serial.print("# of mapped regions (hblks): "); 43 | Serial.println(mi.hblks); 44 | Serial.print("Bytes in mapped regions (hblkhd): "); 45 | Serial.println(mi.hblkhd); 46 | Serial.print("Max. total allocated space (usmblks): "); 47 | Serial.println(mi.usmblks); 48 | Serial.print("Free bytes held in fastbins (fsmblks): "); 49 | Serial.println(mi.fsmblks); 50 | Serial.print("Total allocated space (uordblks): "); 51 | Serial.println(mi.uordblks); 52 | Serial.print("Total free space (fordblks): "); 53 | Serial.println(mi.fordblks); 54 | Serial.print("Topmost releasable block (keepcost): "); 55 | Serial.println(mi.keepcost); 56 | 57 | Serial.print("RAM Start at: 0x"); 58 | Serial.println((unsigned long)ramstart, HEX); 59 | Serial.print("Data/Bss end at: 0x"); 60 | Serial.println((unsigned long)&_end, HEX); 61 | Serial.print("Heap end at: 0x"); 62 | Serial.println((unsigned long)heapend, HEX); 63 | Serial.print("Stack Ptr end at: 0x"); 64 | Serial.println((unsigned long)stack_ptr, HEX); 65 | Serial.print("RAM End at: 0x"); 66 | Serial.println((unsigned long)ramend, HEX); 67 | 68 | Serial.print("Heap RAM Used: "); 69 | Serial.println(mi.uordblks); 70 | Serial.print("Program RAM Used: "); 71 | Serial.println(&_end - ramstart); 72 | Serial.print("Stack RAM Used: "); 73 | Serial.println(ramend - stack_ptr); 74 | Serial.print("Estimated Free RAM: "); 75 | Serial.println(((stack_ptr < minSP) ? stack_ptr : minSP) - heapend + mi.fordblks); 76 | } 77 | 78 | void setup() { 79 | // initialize serial communication at 115200 bits per second: 80 | Serial.begin(115200); 81 | delay(1000); 82 | } 83 | 84 | void loop() { 85 | unsigned int n = 0; 86 | char *alloc[NUM_BLOCKS]; 87 | 88 | Serial.println("============== Before allocating blocks =============="); 89 | display_mallinfo(); 90 | 91 | for (n = 0; n < NUM_BLOCKS; n++) { 92 | alloc[n] = (char*)malloc(BLOCK_SIZE); 93 | if (alloc[n] == NULL) { 94 | Serial.print("Failed to allocate blocks "); 95 | Serial.println(n); 96 | while (1); 97 | } 98 | } 99 | 100 | Serial.println("============== After allocating blocks =============="); 101 | display_mallinfo(); 102 | 103 | for (n = 0; n < NUM_BLOCKS; n++) 104 | free(alloc[n]); 105 | 106 | Serial.println("============== After freeing blocks =============="); 107 | display_mallinfo(); 108 | while (1); 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /examples/Benchmarking/Whetstone/DoublePrecision/DoublePrecision.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on: 3 | * https://os.mbed.com/users/kirchnet/code/Nucleo_vs_Arduino_Speed_Test/ 4 | * 5 | * This is the same whetstone code with adjustments for the 6 | * Serial.print function on the Arduino 7 | * The main loop within the procedure whetstone() is identical. 8 | * Only the output format is Arduino-specific. 9 | */ 10 | int whetstone(void); 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | Serial.println("Starting Whetstone benchmark..."); 15 | } 16 | 17 | void loop() { 18 | whetstone(); 19 | } 20 | 21 | /* 22 | * Source: http://www.netlib.org/benchmark/whetstonec 23 | * 24 | * C Converted Whetstone Double Precision Benchmark 25 | * Version 1.2 22 March 1998 26 | * 27 | * (c) Copyright 1998 Painter Engineering, Inc. 28 | * All Rights Reserved. 29 | * 30 | * Permission is granted to use, duplicate, and 31 | * publish this text and program as long as it 32 | * includes this entire comment block and limited 33 | * rights reference. 34 | * 35 | * Converted by Rich Painter, Painter Engineering, Inc. based on the 36 | * www.netlib.org benchmark/whetstoned version obtained 16 March 1998. 37 | * 38 | * A novel approach was used here to keep the look and feel of the 39 | * FORTRAN version. Altering the FORTRAN-based array indices, 40 | * starting at element 1, to start at element 0 for C, would require 41 | * numerous changes, including decrementing the variable indices by 1. 42 | * Instead, the array E1[] was declared 1 element larger in C. This 43 | * allows the FORTRAN index range to function without any literal or 44 | * variable indices changes. The array element E1[0] is simply never 45 | * used and does not alter the benchmark results. 46 | * 47 | * The major FORTRAN comment blocks were retained to minimize 48 | * differences between versions. Modules N5 and N12, like in the 49 | * FORTRAN version, have been eliminated here. 50 | * 51 | * An optional command-line argument has been provided [-c] to 52 | * offer continuous repetition of the entire benchmark. 53 | * An optional argument for setting an alternate LOOP count is also 54 | * provided. Define PRINTOUT to cause the POUT() function to print 55 | * outputs at various stages. Final timing measurements should be 56 | * made with the PRINTOUT undefined. 57 | * 58 | * Questions and comments may be directed to the author at 59 | * r.painter@ieee.org 60 | */ 61 | /* 62 | C********************************************************************** 63 | C Benchmark #2 -- Double Precision Whetstone (A001) 64 | C 65 | C o This is a REAL*8 version of 66 | C the Whetstone benchmark program. 67 | C 68 | C o DO-loop semantics are ANSI-66 compatible. 69 | C 70 | C o Final measurements are to be made with all 71 | C WRITE statements and FORMAT sttements removed. 72 | C 73 | C********************************************************************** 74 | */ 75 | 76 | #include 77 | #include 78 | #include 79 | #include 80 | /* the following is optional depending on the timing function used */ 81 | #include 82 | 83 | /* map the FORTRAN math functions, etc. to the C versions */ 84 | #define DSIN sin 85 | #define DCOS cos 86 | #define DATAN atan 87 | #define DLOG log 88 | #define DEXP exp 89 | #define DSQRT sqrt 90 | #define IF if 91 | 92 | /* function prototypes */ 93 | void POUT(long N, long J, long K, double X1, double X2, double X3, double X4); 94 | void PA(double E[]); 95 | void P0(void); 96 | void P3(double X, double Y, double *Z); 97 | #define USAGE "usage: whetdc [-c] [loops]\n" 98 | //#define PRINTOUT 99 | 100 | /* 101 | COMMON T,T1,T2,E1(4),J,K,L 102 | */ 103 | double T,T1,T2,E1[5]; 104 | int J,K,L; 105 | 106 | int 107 | whetstone(void) 108 | { 109 | /* used in the FORTRAN version */ 110 | long I; 111 | long N1, N2, N3, N4, N6, N7, N8, N9, N10, N11; 112 | double X1,X2,X3,X4,X,Y,Z; 113 | long LOOP; 114 | int II, JJ; 115 | 116 | /* added for this version */ 117 | long loopstart; 118 | long startsec, finisec; 119 | float KIPS; 120 | int continuous; 121 | 122 | loopstart = 1000; /* see the note about LOOP below */ 123 | continuous = 0; 124 | 125 | LCONT: 126 | /* 127 | C 128 | C Start benchmark timing at this point. 129 | C 130 | */ 131 | startsec = millis(); 132 | 133 | /* 134 | C 135 | C The actual benchmark starts here. 136 | C 137 | */ 138 | T = .499975; 139 | T1 = 0.50025; 140 | T2 = 2.0; 141 | /* 142 | C 143 | C With loopcount LOOP=10, one million Whetstone instructions 144 | C will be executed in EACH MAJOR LOOP..A MAJOR LOOP IS EXECUTED 145 | C 'II' TIMES TO INCREASE WALL-CLOCK TIMING ACCURACY. 146 | C 147 | LOOP = 1000; 148 | */ 149 | LOOP = loopstart; 150 | II = 1; 151 | 152 | JJ = 1; 153 | 154 | IILOOP: 155 | N1 = 0; 156 | N2 = 12 * LOOP; 157 | N3 = 14 * LOOP; 158 | N4 = 345 * LOOP; 159 | N6 = 210 * LOOP; 160 | N7 = 32 * LOOP; 161 | N8 = 899 * LOOP; 162 | N9 = 616 * LOOP; 163 | N10 = 0; 164 | N11 = 93 * LOOP; 165 | /* 166 | C 167 | C Module 1: Simple identifiers 168 | C 169 | */ 170 | X1 = 1.0; 171 | X2 = -1.0; 172 | X3 = -1.0; 173 | X4 = -1.0; 174 | 175 | for (I = 1; I <= N1; I++) { 176 | X1 = (X1 + X2 + X3 - X4) * T; 177 | X2 = (X1 + X2 - X3 + X4) * T; 178 | X3 = (X1 - X2 + X3 + X4) * T; 179 | X4 = (-X1+ X2 + X3 + X4) * T; 180 | } 181 | #ifdef PRINTOUT 182 | IF (JJ==II)POUT(N1,N1,N1,X1,X2,X3,X4); 183 | #endif 184 | 185 | /* 186 | C 187 | C Module 2: Array elements 188 | C 189 | */ 190 | E1[1] = 1.0; 191 | E1[2] = -1.0; 192 | E1[3] = -1.0; 193 | E1[4] = -1.0; 194 | 195 | for (I = 1; I <= N2; I++) { 196 | E1[1] = ( E1[1] + E1[2] + E1[3] - E1[4]) * T; 197 | E1[2] = ( E1[1] + E1[2] - E1[3] + E1[4]) * T; 198 | E1[3] = ( E1[1] - E1[2] + E1[3] + E1[4]) * T; 199 | E1[4] = (-E1[1] + E1[2] + E1[3] + E1[4]) * T; 200 | } 201 | 202 | #ifdef PRINTOUT 203 | IF (JJ==II)POUT(N2,N3,N2,E1[1],E1[2],E1[3],E1[4]); 204 | #endif 205 | 206 | /* 207 | C 208 | C Module 3: Array as parameter 209 | C 210 | */ 211 | for (I = 1; I <= N3; I++) 212 | PA(E1); 213 | 214 | #ifdef PRINTOUT 215 | IF (JJ==II)POUT(N3,N2,N2,E1[1],E1[2],E1[3],E1[4]); 216 | #endif 217 | 218 | /* 219 | C 220 | C Module 4: Conditional jumps 221 | C 222 | */ 223 | J = 1; 224 | for (I = 1; I <= N4; I++) { 225 | if (J == 1) 226 | J = 2; 227 | else 228 | J = 3; 229 | 230 | if (J > 2) 231 | J = 0; 232 | else 233 | J = 1; 234 | 235 | if (J < 1) 236 | J = 1; 237 | else 238 | J = 0; 239 | } 240 | 241 | #ifdef PRINTOUT 242 | IF (JJ==II)POUT(N4,J,J,X1,X2,X3,X4); 243 | #endif 244 | 245 | /* 246 | C 247 | C Module 5: Omitted 248 | C Module 6: Integer arithmetic 249 | C 250 | */ 251 | 252 | J = 1; 253 | K = 2; 254 | L = 3; 255 | 256 | for (I = 1; I <= N6; I++) { 257 | J = J * (K-J) * (L-K); 258 | K = L * K - (L-J) * K; 259 | L = (L-K) * (K+J); 260 | E1[L-1] = J + K + L; 261 | E1[K-1] = J * K * L; 262 | } 263 | 264 | #ifdef PRINTOUT 265 | IF (JJ==II)POUT(N6,J,K,E1[1],E1[2],E1[3],E1[4]); 266 | #endif 267 | 268 | /* 269 | C 270 | C Module 7: Trigonometric functions 271 | C 272 | */ 273 | X = 0.5; 274 | Y = 0.5; 275 | 276 | for (I = 1; I <= N7; I++) { 277 | X = T * DATAN(T2*DSIN(X)*DCOS(X)/(DCOS(X+Y)+DCOS(X-Y)-1.0)); 278 | Y = T * DATAN(T2*DSIN(Y)*DCOS(Y)/(DCOS(X+Y)+DCOS(X-Y)-1.0)); 279 | } 280 | 281 | #ifdef PRINTOUT 282 | IF (JJ==II)POUT(N7,J,K,X,X,Y,Y); 283 | #endif 284 | 285 | /* 286 | C 287 | C Module 8: Procedure calls 288 | C 289 | */ 290 | X = 1.0; 291 | Y = 1.0; 292 | Z = 1.0; 293 | 294 | for (I = 1; I <= N8; I++) 295 | P3(X,Y,&Z); 296 | 297 | #ifdef PRINTOUT 298 | IF (JJ==II)POUT(N8,J,K,X,Y,Z,Z); 299 | #endif 300 | 301 | /* 302 | C 303 | C Module 9: Array references 304 | C 305 | */ 306 | J = 1; 307 | K = 2; 308 | L = 3; 309 | E1[1] = 1.0; 310 | E1[2] = 2.0; 311 | E1[3] = 3.0; 312 | 313 | for (I = 1; I <= N9; I++) 314 | P0(); 315 | 316 | #ifdef PRINTOUT 317 | IF (JJ==II)POUT(N9,J,K,E1[1],E1[2],E1[3],E1[4]); 318 | #endif 319 | 320 | /* 321 | C 322 | C Module 10: Integer arithmetic 323 | C 324 | */ 325 | J = 2; 326 | K = 3; 327 | 328 | for (I = 1; I <= N10; I++) { 329 | J = J + K; 330 | K = J + K; 331 | J = K - J; 332 | K = K - J - J; 333 | } 334 | 335 | #ifdef PRINTOUT 336 | IF (JJ==II)POUT(N10,J,K,X1,X2,X3,X4); 337 | #endif 338 | 339 | /* 340 | C 341 | C Module 11: Standard functions 342 | C 343 | */ 344 | X = 0.75; 345 | 346 | for (I = 1; I <= N11; I++) 347 | X = DSQRT(DEXP(DLOG(X)/T1)); 348 | 349 | #ifdef PRINTOUT 350 | IF (JJ==II)POUT(N11,J,K,X,X,X,X); 351 | #endif 352 | 353 | /* 354 | C 355 | C THIS IS THE END OF THE MAJOR LOOP. 356 | C 357 | */ 358 | if (++JJ <= II) 359 | goto IILOOP; 360 | 361 | /* 362 | C 363 | C Stop benchmark timing at this point. 364 | C 365 | */ 366 | finisec = millis(); 367 | 368 | /* 369 | C---------------------------------------------------------------- 370 | C Performance in Whetstone KIP's per second is given by 371 | C 372 | C (100*LOOP*II)/TIME 373 | C 374 | C where TIME is in seconds. 375 | C-------------------------------------------------------------------- 376 | */ 377 | Serial.write("\n"); 378 | if (finisec-startsec <= 0) { 379 | Serial.write("Insufficient duration- Increase the LOOP count\n"); 380 | return(1); 381 | } 382 | 383 | Serial.print("Loops: "); 384 | Serial.print(LOOP); 385 | Serial.print(" Iterations: "); 386 | Serial.print(II); 387 | Serial.print(" Duration: "); 388 | Serial.print(finisec-startsec); 389 | Serial.println(" millisec.");//Arduino measures time in milliseconds 390 | 391 | // KIPS = (100.0*LOOP*II)/(float)(finisec-startsec); 392 | KIPS = (100.0*LOOP*II)/(float)(finisec-startsec)*1000;//convert to seconds from milliseconds 393 | if (KIPS >= 1000.0){ 394 | Serial.print("C Converted Double Precision Whetstones: "); 395 | Serial.print(KIPS/1000.0); 396 | Serial.println(" MIPS"); 397 | } 398 | else{ 399 | Serial.print("C Converted Double Precision Whetstones: "); 400 | Serial.print(KIPS); 401 | Serial.println(" KIPS"); 402 | } 403 | 404 | if (continuous) 405 | goto LCONT; 406 | 407 | return(0); 408 | } 409 | 410 | void 411 | PA(double E[]) 412 | { 413 | J = 0; 414 | 415 | L10: 416 | E[1] = ( E[1] + E[2] + E[3] - E[4]) * T; 417 | E[2] = ( E[1] + E[2] - E[3] + E[4]) * T; 418 | E[3] = ( E[1] - E[2] + E[3] + E[4]) * T; 419 | E[4] = (-E[1] + E[2] + E[3] + E[4]) / T2; 420 | J += 1; 421 | 422 | if (J < 6) 423 | goto L10; 424 | } 425 | 426 | void 427 | P0(void) 428 | { 429 | E1[J] = E1[K]; 430 | E1[K] = E1[L]; 431 | E1[L] = E1[J]; 432 | } 433 | 434 | void 435 | P3(double X, double Y, double *Z) 436 | { 437 | double X1, Y1; 438 | 439 | X1 = X; 440 | Y1 = Y; 441 | X1 = T * (X1 + Y1); 442 | Y1 = T * (X1 + Y1); 443 | *Z = (X1 + Y1) / T2; 444 | } 445 | 446 | #ifdef PRINTOUT 447 | void 448 | POUT(long N, long J, long K, double X1, double X2, double X3, double X4) 449 | { 450 | //sprintf("%7ld %7ld %7ld %12.4e %12.4e %12.4e %12.4e\n", 451 | // N, J, K, X1, X2, X3, X4); 452 | Serial.print(N); 453 | Serial.print("\t"); 454 | Serial.print(J); 455 | Serial.print("\t"); 456 | Serial.print(K); 457 | Serial.print("\t"); 458 | Serial.print(X1); 459 | Serial.print("\t"); 460 | Serial.print(X2); 461 | Serial.print("\t"); 462 | Serial.print(X3); 463 | Serial.print("\t"); 464 | Serial.print(X4); 465 | Serial.print("\t"); 466 | Serial.println(N); 467 | } 468 | #endif 469 | 470 | -------------------------------------------------------------------------------- /examples/Benchmarking/Whetstone/SinglePrecision/SinglePrecision.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on: 3 | * https://os.mbed.com/users/kirchnet/code/Nucleo_vs_Arduino_Speed_Test/ 4 | * 5 | * This is the same whetstone code with adjustments for the 6 | * Serial.print function on the Arduino 7 | * The main loop within the procedure whetstone() is identical. 8 | * Only the output format is Arduino-specific. 9 | * Updated to use single-precision floats instead of 10 | * double-precision doubles 11 | */ 12 | int whetstone(void); 13 | 14 | void setup() { 15 | Serial.begin(115200); 16 | Serial.println("Starting Whetstone benchmark..."); 17 | } 18 | 19 | void loop() { 20 | whetstone(); 21 | } 22 | 23 | /* 24 | * Source: http://www.netlib.org/benchmark/whetstonec 25 | * 26 | * C Converted Whetstone Single Precision Benchmark 27 | * Version 1.2 22 March 1998 28 | * 29 | * (c) Copyright 1998 Painter Engineering, Inc. 30 | * All Rights Reserved. 31 | * 32 | * Permission is granted to use, duplicate, and 33 | * publish this text and program as long as it 34 | * includes this entire comment block and limited 35 | * rights reference. 36 | * 37 | * Converted by Rich Painter, Painter Engineering, Inc. based on the 38 | * www.netlib.org benchmark/whetstoned version obtained 16 March 1998. 39 | * 40 | * A novel approach was used here to keep the look and feel of the 41 | * FORTRAN version. Altering the FORTRAN-based array indices, 42 | * starting at element 1, to start at element 0 for C, would require 43 | * numerous changes, including decrementing the variable indices by 1. 44 | * Instead, the array E1[] was declared 1 element larger in C. This 45 | * allows the FORTRAN index range to function without any literal or 46 | * variable indices changes. The array element E1[0] is simply never 47 | * used and does not alter the benchmark results. 48 | * 49 | * The major FORTRAN comment blocks were retained to minimize 50 | * differences between versions. Modules N5 and N12, like in the 51 | * FORTRAN version, have been eliminated here. 52 | * 53 | * An optional command-line argument has been provided [-c] to 54 | * offer continuous repetition of the entire benchmark. 55 | * An optional argument for setting an alternate LOOP count is also 56 | * provided. Define PRINTOUT to cause the POUT() function to print 57 | * outputs at various stages. Final timing measurements should be 58 | * made with the PRINTOUT undefined. 59 | * 60 | * Questions and comments may be directed to the author at 61 | * r.painter@ieee.org 62 | */ 63 | /* 64 | C********************************************************************** 65 | C Benchmark #2 -- Single Precision Whetstone (A001) 66 | C 67 | C o This is a REAL*8 version of 68 | C the Whetstone benchmark program. 69 | C 70 | C o DO-loop semantics are ANSI-66 compatible. 71 | C 72 | C o Final measurements are to be made with all 73 | C WRITE statements and FORMAT sttements removed. 74 | C 75 | C********************************************************************** 76 | */ 77 | 78 | #include 79 | #include 80 | #include 81 | #include 82 | /* the following is optional depending on the timing function used */ 83 | #include 84 | 85 | /* map the FORTRAN math functions, etc. to the C versions */ 86 | #define DSIN sinf 87 | #define DCOS cosf 88 | #define DATAN atanf 89 | #define DLOG logf 90 | #define DEXP expf 91 | #define DSQRT sqrtf 92 | #define IF if 93 | 94 | /* function prototypes */ 95 | void POUT(long N, long J, long K, float X1, float X2, float X3, float X4); 96 | void PA(float E[]); 97 | void P0(void); 98 | void P3(float X, float Y, float *Z); 99 | #define USAGE "usage: whetdc [-c] [loops]\n" 100 | //#define PRINTOUT 101 | 102 | /* 103 | COMMON T,T1,T2,E1(4),J,K,L 104 | */ 105 | float T,T1,T2,E1[5]; 106 | int J,K,L; 107 | 108 | int 109 | whetstone(void) 110 | { 111 | /* used in the FORTRAN version */ 112 | long I; 113 | long N1, N2, N3, N4, N6, N7, N8, N9, N10, N11; 114 | float X1,X2,X3,X4,X,Y,Z; 115 | long LOOP; 116 | int II, JJ; 117 | 118 | /* added for this version */ 119 | long loopstart; 120 | long startsec, finisec; 121 | float KIPS; 122 | int continuous; 123 | 124 | loopstart = 1000; /* see the note about LOOP below */ 125 | continuous = 0; 126 | 127 | LCONT: 128 | /* 129 | C 130 | C Start benchmark timing at this point. 131 | C 132 | */ 133 | startsec = millis(); 134 | 135 | /* 136 | C 137 | C The actual benchmark starts here. 138 | C 139 | */ 140 | T = .499975; 141 | T1 = 0.50025; 142 | T2 = 2.0; 143 | /* 144 | C 145 | C With loopcount LOOP=10, one million Whetstone instructions 146 | C will be executed in EACH MAJOR LOOP..A MAJOR LOOP IS EXECUTED 147 | C 'II' TIMES TO INCREASE WALL-CLOCK TIMING ACCURACY. 148 | C 149 | LOOP = 1000; 150 | */ 151 | LOOP = loopstart; 152 | II = 1; 153 | 154 | JJ = 1; 155 | 156 | IILOOP: 157 | N1 = 0; 158 | N2 = 12 * LOOP; 159 | N3 = 14 * LOOP; 160 | N4 = 345 * LOOP; 161 | N6 = 210 * LOOP; 162 | N7 = 32 * LOOP; 163 | N8 = 899 * LOOP; 164 | N9 = 616 * LOOP; 165 | N10 = 0; 166 | N11 = 93 * LOOP; 167 | /* 168 | C 169 | C Module 1: Simple identifiers 170 | C 171 | */ 172 | X1 = 1.0; 173 | X2 = -1.0; 174 | X3 = -1.0; 175 | X4 = -1.0; 176 | 177 | for (I = 1; I <= N1; I++) { 178 | X1 = (X1 + X2 + X3 - X4) * T; 179 | X2 = (X1 + X2 - X3 + X4) * T; 180 | X3 = (X1 - X2 + X3 + X4) * T; 181 | X4 = (-X1+ X2 + X3 + X4) * T; 182 | } 183 | #ifdef PRINTOUT 184 | IF (JJ==II)POUT(N1,N1,N1,X1,X2,X3,X4); 185 | #endif 186 | 187 | /* 188 | C 189 | C Module 2: Array elements 190 | C 191 | */ 192 | E1[1] = 1.0; 193 | E1[2] = -1.0; 194 | E1[3] = -1.0; 195 | E1[4] = -1.0; 196 | 197 | for (I = 1; I <= N2; I++) { 198 | E1[1] = ( E1[1] + E1[2] + E1[3] - E1[4]) * T; 199 | E1[2] = ( E1[1] + E1[2] - E1[3] + E1[4]) * T; 200 | E1[3] = ( E1[1] - E1[2] + E1[3] + E1[4]) * T; 201 | E1[4] = (-E1[1] + E1[2] + E1[3] + E1[4]) * T; 202 | } 203 | 204 | #ifdef PRINTOUT 205 | IF (JJ==II)POUT(N2,N3,N2,E1[1],E1[2],E1[3],E1[4]); 206 | #endif 207 | 208 | /* 209 | C 210 | C Module 3: Array as parameter 211 | C 212 | */ 213 | for (I = 1; I <= N3; I++) 214 | PA(E1); 215 | 216 | #ifdef PRINTOUT 217 | IF (JJ==II)POUT(N3,N2,N2,E1[1],E1[2],E1[3],E1[4]); 218 | #endif 219 | 220 | /* 221 | C 222 | C Module 4: Conditional jumps 223 | C 224 | */ 225 | J = 1; 226 | for (I = 1; I <= N4; I++) { 227 | if (J == 1) 228 | J = 2; 229 | else 230 | J = 3; 231 | 232 | if (J > 2) 233 | J = 0; 234 | else 235 | J = 1; 236 | 237 | if (J < 1) 238 | J = 1; 239 | else 240 | J = 0; 241 | } 242 | 243 | #ifdef PRINTOUT 244 | IF (JJ==II)POUT(N4,J,J,X1,X2,X3,X4); 245 | #endif 246 | 247 | /* 248 | C 249 | C Module 5: Omitted 250 | C Module 6: Integer arithmetic 251 | C 252 | */ 253 | 254 | J = 1; 255 | K = 2; 256 | L = 3; 257 | 258 | for (I = 1; I <= N6; I++) { 259 | J = J * (K-J) * (L-K); 260 | K = L * K - (L-J) * K; 261 | L = (L-K) * (K+J); 262 | E1[L-1] = J + K + L; 263 | E1[K-1] = J * K * L; 264 | } 265 | 266 | #ifdef PRINTOUT 267 | IF (JJ==II)POUT(N6,J,K,E1[1],E1[2],E1[3],E1[4]); 268 | #endif 269 | 270 | /* 271 | C 272 | C Module 7: Trigonometric functions 273 | C 274 | */ 275 | X = 0.5; 276 | Y = 0.5; 277 | 278 | for (I = 1; I <= N7; I++) { 279 | X = T * DATAN(T2*DSIN(X)*DCOS(X)/(DCOS(X+Y)+DCOS(X-Y)-1.0)); 280 | Y = T * DATAN(T2*DSIN(Y)*DCOS(Y)/(DCOS(X+Y)+DCOS(X-Y)-1.0)); 281 | } 282 | 283 | #ifdef PRINTOUT 284 | IF (JJ==II)POUT(N7,J,K,X,X,Y,Y); 285 | #endif 286 | 287 | /* 288 | C 289 | C Module 8: Procedure calls 290 | C 291 | */ 292 | X = 1.0; 293 | Y = 1.0; 294 | Z = 1.0; 295 | 296 | for (I = 1; I <= N8; I++) 297 | P3(X,Y,&Z); 298 | 299 | #ifdef PRINTOUT 300 | IF (JJ==II)POUT(N8,J,K,X,Y,Z,Z); 301 | #endif 302 | 303 | /* 304 | C 305 | C Module 9: Array references 306 | C 307 | */ 308 | J = 1; 309 | K = 2; 310 | L = 3; 311 | E1[1] = 1.0; 312 | E1[2] = 2.0; 313 | E1[3] = 3.0; 314 | 315 | for (I = 1; I <= N9; I++) 316 | P0(); 317 | 318 | #ifdef PRINTOUT 319 | IF (JJ==II)POUT(N9,J,K,E1[1],E1[2],E1[3],E1[4]); 320 | #endif 321 | 322 | /* 323 | C 324 | C Module 10: Integer arithmetic 325 | C 326 | */ 327 | J = 2; 328 | K = 3; 329 | 330 | for (I = 1; I <= N10; I++) { 331 | J = J + K; 332 | K = J + K; 333 | J = K - J; 334 | K = K - J - J; 335 | } 336 | 337 | #ifdef PRINTOUT 338 | IF (JJ==II)POUT(N10,J,K,X1,X2,X3,X4); 339 | #endif 340 | 341 | /* 342 | C 343 | C Module 11: Standard functions 344 | C 345 | */ 346 | X = 0.75; 347 | 348 | for (I = 1; I <= N11; I++) 349 | X = DSQRT(DEXP(DLOG(X)/T1)); 350 | 351 | #ifdef PRINTOUT 352 | IF (JJ==II)POUT(N11,J,K,X,X,X,X); 353 | #endif 354 | 355 | /* 356 | C 357 | C THIS IS THE END OF THE MAJOR LOOP. 358 | C 359 | */ 360 | if (++JJ <= II) 361 | goto IILOOP; 362 | 363 | /* 364 | C 365 | C Stop benchmark timing at this point. 366 | C 367 | */ 368 | finisec = millis(); 369 | 370 | /* 371 | C---------------------------------------------------------------- 372 | C Performance in Whetstone KIP's per second is given by 373 | C 374 | C (100*LOOP*II)/TIME 375 | C 376 | C where TIME is in seconds. 377 | C-------------------------------------------------------------------- 378 | */ 379 | Serial.write("\n"); 380 | if (finisec-startsec <= 0) { 381 | Serial.write("Insufficient duration- Increase the LOOP count\n"); 382 | return(1); 383 | } 384 | 385 | Serial.print("Loops: "); 386 | Serial.print(LOOP); 387 | Serial.print(" Iterations: "); 388 | Serial.print(II); 389 | Serial.print(" Duration: "); 390 | Serial.print(finisec-startsec); 391 | Serial.println(" millisec.");//Arduino measures time in milliseconds 392 | 393 | // KIPS = (100.0*LOOP*II)/(float)(finisec-startsec); 394 | KIPS = (100.0*LOOP*II)/(float)(finisec-startsec)*1000;//convert to seconds from milliseconds 395 | if (KIPS >= 1000.0){ 396 | Serial.print("C Converted Single Precision Whetstones: "); 397 | Serial.print(KIPS/1000.0); 398 | Serial.println(" MIPS"); 399 | } 400 | else{ 401 | Serial.print("C Converted Single Precision Whetstones: "); 402 | Serial.print(KIPS); 403 | Serial.println(" KIPS"); 404 | } 405 | 406 | if (continuous) 407 | goto LCONT; 408 | 409 | return(0); 410 | } 411 | 412 | void 413 | PA(float E[]) 414 | { 415 | J = 0; 416 | 417 | L10: 418 | E[1] = ( E[1] + E[2] + E[3] - E[4]) * T; 419 | E[2] = ( E[1] + E[2] - E[3] + E[4]) * T; 420 | E[3] = ( E[1] - E[2] + E[3] + E[4]) * T; 421 | E[4] = (-E[1] + E[2] + E[3] + E[4]) / T2; 422 | J += 1; 423 | 424 | if (J < 6) 425 | goto L10; 426 | } 427 | 428 | void 429 | P0(void) 430 | { 431 | E1[J] = E1[K]; 432 | E1[K] = E1[L]; 433 | E1[L] = E1[J]; 434 | } 435 | 436 | void 437 | P3(float X, float Y, float *Z) 438 | { 439 | float X1, Y1; 440 | 441 | X1 = X; 442 | Y1 = Y; 443 | X1 = T * (X1 + Y1); 444 | Y1 = T * (X1 + Y1); 445 | *Z = (X1 + Y1) / T2; 446 | } 447 | 448 | #ifdef PRINTOUT 449 | void 450 | POUT(long N, long J, long K, float X1, float X2, float X3, float X4) 451 | { 452 | //sprintf("%7ld %7ld %7ld %12.4e %12.4e %12.4e %12.4e\n", 453 | // N, J, K, X1, X2, X3, X4); 454 | Serial.print(N); 455 | Serial.print("\t"); 456 | Serial.print(J); 457 | Serial.print("\t"); 458 | Serial.print(K); 459 | Serial.print("\t"); 460 | Serial.print(X1); 461 | Serial.print("\t"); 462 | Serial.print(X2); 463 | Serial.print("\t"); 464 | Serial.print(X3); 465 | Serial.print("\t"); 466 | Serial.print(X4); 467 | Serial.print("\t"); 468 | Serial.println(N); 469 | } 470 | #endif 471 | 472 | 473 | -------------------------------------------------------------------------------- /examples/Boards/STM32F746NG-DISCOVERY/Ethernet_MQTT_Adafruit.io/Ethernet_MQTT_Adafruit.io.ino: -------------------------------------------------------------------------------- 1 | /* 2 | STM32F746G-DISCOVERY MQTT example to publish on https://io.adafruit.com broker 3 | 4 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/overview 5 | 6 | This sketch demonstrates the capabilities of the pubsub library in combination 7 | with the STM32F746G-DISCOVERY board. 8 | 9 | It will use several components of the board and you need to install corresponding libraries : 10 | - Ethernet (STM32Ethernet) : https://github.com/stm32duino/STM32Ethernet 11 | - Temperature and humidity sensor (HTS221) : https://github.com/stm32duino/HTS221 12 | - Arduino Client for MQTT: https://github.com/knolleary/pubsubclient 13 | 14 | To get temperature and humidity you will need the X-NUCLEO-IKS01A1, a motion MEMS and 15 | environmental sensor expansion board for the STM32 board. 16 | 17 | You can find more information on the board and exapansion board here : 18 | http://www.st.com/en/evaluation-tools/32f746gdiscovery.html 19 | http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-sense-hw/x-nucleo-iks01a1.html) 20 | 21 | You will need to create some feeds in your Adafruit IO Dashboard. 22 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/getting-started-on-adafruit-io 23 | to know how register and create your Adafruit IO dashboard and feeds: 24 | - hello: Text block 25 | - onoff: Toggle block 26 | - temp: Stream block 27 | - hum: Gauge block 28 | A screenshot of the dashboard is available in the img/ directory: dashboard_adafruit.png 29 | 30 | It connects to the Adafruit IO's MQTT server (a.k.a broker) server then: 31 | - publishes announcement "Hi, I'm STM32 user!" to the topic 'AIO_USERNAME"/feeds/hello"' 32 | - subscribes to the topic AIO_USERNAME"/feeds/onoff"', switching LED_BUILTIN state 33 | - publishes temperature and humidity from the HTS221 sensor to the topic 34 | 'AIO_USERNAME"/feeds/temp"' and 'AIO_USERNAME"/feeds/hum"' every 10 seconds 35 | 36 | It will reconnect to the server if the connection is lost using a blocking 37 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 38 | achieve the same result without blocking the main loop. 39 | 40 | */ 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | // Adafruit.io Setup 47 | #define AIO_SERVER "io.adafruit.com" 48 | #define AIO_SERVERPORT 1883 49 | #define AIO_USERNAME "......" 50 | #define AIO_KEY "........" 51 | 52 | // Etherrnet setup 53 | // Update these with values suitable for your network. 54 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 55 | // Set the static IP address to use if the DHCP fails to assign 56 | IPAddress ip(192, 168, 0, 177); 57 | EthernetClient STClient; 58 | 59 | // i2c sensors 60 | HTS221Sensor *HumTemp; 61 | 62 | PubSubClient client(STClient); 63 | long lastMsg = 0; 64 | char msg[8]; 65 | 66 | void setup() { 67 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 68 | Serial.begin(115200); 69 | 70 | client.setServer(AIO_SERVER, AIO_SERVERPORT); 71 | client.setCallback(callback); 72 | 73 | // Start the Ethernet connection: 74 | if (Ethernet.begin(mac) == 0) { 75 | Serial.println("Failed to configure Ethernet using DHCP"); 76 | // Try to congifure using IP address instead of DHCP: 77 | Ethernet.begin(mac, ip); 78 | } 79 | // Allow the hardware to sort itself out 80 | delay(1500); 81 | 82 | // Initialize I2C bus. 83 | Wire.begin(); 84 | 85 | // Initlialize components. 86 | HumTemp = new HTS221Sensor (&Wire); 87 | HumTemp->Enable(); 88 | } 89 | 90 | void callback(char* topic, byte* payload, unsigned int length) { 91 | 92 | #if 0 93 | Serial.print("Message arrived ["); 94 | Serial.print(topic); 95 | Serial.print("] "); 96 | for (unsigned int i = 0; i < length; i++) { 97 | Serial.print((char)payload[i]); 98 | } 99 | Serial.println(); 100 | #else 101 | UNUSED(topic); 102 | #endif 103 | if (length > 1) { 104 | // Switch on/off the LED (payload messages can be 'ON' or 'OFF') 105 | if ((char)payload[1] == 'N') { 106 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on 107 | } else { 108 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED off 109 | } 110 | } 111 | } 112 | 113 | void reconnect() { 114 | // Loop until we're reconnected 115 | while (!client.connected()) { 116 | Serial.print("Attempting MQTT connection..."); 117 | // Attempt to connect 118 | // Note - the default maximum packet size is 128 bytes. If the 119 | // combined length of clientId, username and password exceed this, 120 | // you will need to increase the value of MQTT_MAX_PACKET_SIZE in 121 | // PubSubClient.h 122 | if (client.connect("STM32Client", AIO_USERNAME, AIO_KEY)) { 123 | Serial.println("connected"); 124 | // Once connected, publish an announcement... 125 | client.publish(AIO_USERNAME"/feeds/hello", "Hi, I'm STM32 user!"); 126 | // ... and resubscribe 127 | client.subscribe(AIO_USERNAME"/feeds/onoff"); 128 | } else { 129 | Serial.print("failed, rc="); 130 | Serial.print(client.state()); 131 | Serial.println(" try again in 5 seconds"); 132 | // Wait 5 seconds before retrying 133 | delay(5000); 134 | } 135 | } 136 | } 137 | 138 | void loop() { 139 | float temperature, humidity; 140 | if (!client.connected()) { 141 | reconnect(); 142 | } 143 | client.loop(); 144 | 145 | long now = millis(); 146 | if (now - lastMsg > 10000) { 147 | lastMsg = now; 148 | HumTemp->GetTemperature(&temperature); 149 | dtostrf(temperature, 2, 2, msg); 150 | Serial.print("Publish temperature "); 151 | Serial.println(msg); 152 | client.publish(AIO_USERNAME"/feeds/temp", msg); 153 | 154 | HumTemp->GetHumidity(&humidity); 155 | snprintf (msg, 8, "%u", (unsigned int)humidity); 156 | Serial.print("Publish humidity "); 157 | Serial.println(msg); 158 | client.publish(AIO_USERNAME"/feeds/hum", msg); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /examples/Boards/STM32F746NG-DISCOVERY/Ethernet_MQTT_Adafruit.io/README.md: -------------------------------------------------------------------------------- 1 | # Ethernet_MQTT_Adafruit.io 2 | 3 | This example demonstrates the capabilities of the [PubSubClient](https://github.com/knolleary/pubsubclient) library in combination 4 | with the [STM32F746G-DISCOVERY](http://www.st.com/en/evaluation-tools/32f746gdiscovery.html) board to publish on https://io.adafruit.com broker 5 | 6 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/overview 7 | 8 | # Dependencies 9 | 10 | Install the following libraries using the Arduino IDE: **_Sketch -> Include Library -> Manage Libraries_** and search: 11 | 12 | * [PubSubClient](https://github.com/knolleary/pubsubclient): Arduino Client for MQTT. 13 | * [STM32 Ethernet](https://github.com/stm32duino/STM32Ethernet): Ethernet library for STM32 based board with on-board Ethernet connector. 14 | * [STM32duino HTS221](https://github.com/stm32duino/HTS221): Ethernet library for STM32 based board with on-board Ethernet connector. 15 | 16 | # Hardware 17 | 18 | To get temperature and humidity you will need the [X-NUCLEO-IKS01A1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-sense-hw/x-nucleo-iks01a1.html), a motion MEMS and environmental sensor expansion board for the STM32 board. 19 | 20 | # Adafruit IO Dashboard. 21 | 22 | You will need to create some feeds in your Adafruit IO Dashboard. 23 | 24 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/getting-started-on-adafruit-io 25 | 26 | to know how register and create your Adafruit IO dashboard and feeds: 27 | * hello: Text block 28 | * onoff: Toggle block 29 | * temp: Stream block 30 | * hum: Gauge block 31 | 32 | A screenshot of the dashboard: 33 | [Dashboard Adafruit](/img/dashboard_adafruit.png) 34 | 35 | It connects to the Adafruit IO's MQTT server (a.k.a broker) server then: 36 | * publishes announcement "_Hi, I'm STM32 user!_" to the topic `AIO_USERNAME"/feeds/hello"` 37 | * subscribes to the topic `AIO_USERNAME"/feeds/onoff"`, switching `LED_BUILTIN` state 38 | * publishes temperature and humidity from the HTS221 sensor to the topic 39 | `AIO_USERNAME"/feeds/temp"` and `AIO_USERNAME"/feeds/hum"` every 10 seconds 40 | -------------------------------------------------------------------------------- /examples/Boards/STM32L475VG-DISCOVERY-IOT/BTLE_sensors_TimeOfFlight_demo/BTLE_sensors_TimeOfFlight_demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | BTLE_sensors_tof_demo 4 | 5 | This sketch provides a default demo to be used on STMicroelectronics Discovery L475VG IoT board. 6 | It will use several components of the board and you need to install corresponding libraries : 7 | * Low energy Bluetooth (SPBTLE_RF) : https://github.com/stm32duino/SPBTLE-RF 8 | * Temperature and pressure sensor (LPS22HB) : https://github.com/stm32duino/LPS22HB 9 | * Temperature and humidity sensor (HTS221) : https://github.com/stm32duino/HTS221 10 | * Time of flight sensor (VL53L0X) : https://github.com/stm32duino/VL53L0X 11 | 12 | You can find more information on this board here : 13 | http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html 14 | 15 | This sketch will launch 3 services on BLE : Acc, Environnemental and Time. 16 | For testing the sketch, you need to download BlueNRG application from playstore provided by 17 | STMicroelectronics. (https://play.google.com/store/apps/details?id=com.st.blunrg for Android or 18 | https://itunes.apple.com/fr/app/bluenrg/id705873549?mt=8 for Apple) 19 | Compile and download the demo on your board, then, on your smartphone, enable Bluetooth, launch 20 | the application and connect it to the BLueNRG device. You will see all the services, you can 21 | click on each one. 22 | 23 | Temperature, humidity and pressure are sent to the environment service and updated on regular 24 | basis. 25 | To move the cube on motion tab, you have to swipe on top of the vl53l0x sensor. To change 26 | direction of the motion, use a tap. The gesture has to be done at less than 1 meter from the 27 | sensor. 28 | 29 | Do not forget to check information on the console. 30 | 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | /* Configure SPI3 for BLE 46 | MOSI: PC12, MISO: PC11, SCLK: PC10 47 | */ 48 | SPIClass SPI_3(PC12, PC11, PC10); 49 | 50 | /* Configure BTLE pins 51 | csPin = PD13, spiIRQ = PE6, reset = PA8, led = LED4 52 | */ 53 | SPBTLERFClass BTLE(&SPI_3, PD13, PE6, PA8, LED4); 54 | 55 | /* BLE device name and address */ 56 | const char *name = "BlueNRG"; 57 | uint8_t SERVER_BDADDR[] = {0x12, 0x34, 0x00, 0xE1, 0x80, 0x03}; // update this value in case you have several demo in the same place... 58 | 59 | /* i2c sensors */ 60 | HTS221Sensor *HumTemp; 61 | LPS22HBSensor *PressTemp; 62 | VL53L0X *sensor_vl53l0x; 63 | 64 | TwoWire *dev_i2c; 65 | #define I2C2_SCL PB10 66 | #define I2C2_SDA PB11 67 | 68 | /* global variables */ 69 | AxesRaw_t axes_data; // structure to update position on BLE motion part 70 | uint32_t previousSecond = 0; // used to trigger environmental data update 71 | Gesture_SWIPE_1_Data_t gestureSwipeData; // vl53l0x swipe detection 72 | Gesture_TAP_1_Data_t gestureTapData; // vl53l0x tap detection 73 | uint32_t distance_top; // used for ToF gesture recognition 74 | uint32_t count_swipe; // count for swipe animation 75 | int axis_to_update; // axis to update on a swipe detection 76 | 77 | #define UPDATE_AXIS_X 0 78 | #define UPDATE_AXIS_Y 1 79 | #define UPDATE_AXIS_Z 2 80 | 81 | 82 | /*************************************************************************************** 83 | * Private functions 84 | ***************************************************************************************/ 85 | 86 | /* Setup vl53l0x for single shot mode */ 87 | void SetupSingleShot(void){ 88 | int status; 89 | uint8_t VhvSettings; 90 | uint8_t PhaseCal; 91 | uint32_t refSpadCount; 92 | uint8_t isApertureSpads; 93 | 94 | status = sensor_vl53l0x->StaticInit(); 95 | if( status ){ 96 | Serial.println("StaticInit sensor failed"); 97 | } 98 | 99 | status = sensor_vl53l0x->PerformRefCalibration(&VhvSettings, &PhaseCal); 100 | if( status ){ 101 | Serial.println("PerformRefCalibration sensor failed"); 102 | } 103 | 104 | status = sensor_vl53l0x->PerformRefSpadManagement(&refSpadCount, &isApertureSpads); 105 | if( status ){ 106 | Serial.println("PerformRefSpadManagement sensor failed"); 107 | } 108 | 109 | status = sensor_vl53l0x->SetDeviceMode(VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode 110 | if( status ){ 111 | Serial.println("SetDeviceMode sensor failed"); 112 | } 113 | 114 | status = sensor_vl53l0x->SetMeasurementTimingBudgetMicroSeconds(20*1000); 115 | if( status ){ 116 | Serial.println("SetMeasurementTimingBudgetMicroSeconds sensor failed"); 117 | } 118 | } 119 | 120 | /* function to detect swipe on vl53l0x */ 121 | bool swipe_detected() { 122 | int gesture_code; 123 | int status; 124 | bool ret = false; 125 | 126 | sensor_vl53l0x->StartMeasurement(); 127 | 128 | int top_done = 0; 129 | uint8_t NewDataReady=0; 130 | VL53L0X_RangingMeasurementData_t pRangingMeasurementData; 131 | 132 | do 133 | { 134 | if(top_done == 0) 135 | { 136 | NewDataReady = 0; 137 | status = sensor_vl53l0x->GetMeasurementDataReady(&NewDataReady); 138 | 139 | if( status ){ 140 | Serial.println("GetMeasurementDataReady sensor failed"); 141 | } 142 | 143 | if(NewDataReady) 144 | { 145 | status = sensor_vl53l0x->ClearInterruptMask(0); 146 | if( status ){ 147 | Serial.println("ClearInterruptMask sensor failed"); 148 | } 149 | 150 | status = sensor_vl53l0x->GetRangingMeasurementData(&pRangingMeasurementData); 151 | if( status ){ 152 | Serial.println("GetRangingMeasurementData sensor failed"); 153 | } 154 | 155 | if (pRangingMeasurementData.RangeStatus == 0) { 156 | // we have a valid range. 157 | distance_top = pRangingMeasurementData.RangeMilliMeter; 158 | }else { 159 | distance_top = 1200; 160 | } 161 | 162 | top_done = 1; 163 | } 164 | } 165 | }while(top_done == 0); 166 | 167 | // Launch gesture detection algorithm. 168 | gesture_code = tof_gestures_detectSWIPE_1(distance_top, &gestureSwipeData); 169 | 170 | // Check the result of the gesture detection algorithm. 171 | switch(gesture_code) 172 | { 173 | case GESTURES_SINGLE_SWIPE: 174 | Serial.println(" => Swipe detected"); 175 | ret = true; 176 | break; 177 | default: 178 | // Do nothing 179 | break; 180 | } 181 | return ret; 182 | } 183 | 184 | /* function to detect tap on vl53l0x */ 185 | bool tap_detected() { 186 | int gesture_code; 187 | int status; 188 | bool ret = false; 189 | 190 | sensor_vl53l0x->StartMeasurement(); 191 | 192 | int top_done = 0; 193 | uint8_t NewDataReady=0; 194 | VL53L0X_RangingMeasurementData_t pRangingMeasurementData; 195 | 196 | do 197 | { 198 | if(top_done == 0) 199 | { 200 | NewDataReady = 0; 201 | status = sensor_vl53l0x->GetMeasurementDataReady(&NewDataReady); 202 | 203 | if( status ){ 204 | Serial.println("GetMeasurementDataReady sensor failed"); 205 | } 206 | 207 | if(NewDataReady) 208 | { 209 | status = sensor_vl53l0x->ClearInterruptMask(0); 210 | if( status ){ 211 | Serial.println("ClearInterruptMask sensor failed"); 212 | } 213 | 214 | status = sensor_vl53l0x->GetRangingMeasurementData(&pRangingMeasurementData); 215 | if( status ){ 216 | Serial.println("GetRangingMeasurementData sensor failed"); 217 | } 218 | 219 | if (pRangingMeasurementData.RangeStatus == 0) { 220 | // we have a valid range. 221 | distance_top = pRangingMeasurementData.RangeMilliMeter; 222 | }else { 223 | distance_top = 1200; 224 | } 225 | 226 | top_done = 1; 227 | } 228 | } 229 | }while(top_done == 0); 230 | 231 | // Launch gesture detection algorithm. 232 | gesture_code = tof_gestures_detectTAP_1(distance_top, &gestureTapData); 233 | 234 | // Check the result of the gesture detection algorithm. 235 | switch(gesture_code) 236 | { 237 | case GESTURES_SINGLE_TAP: 238 | Serial.println(" => Tap detected"); 239 | ret = true; 240 | break; 241 | default: 242 | // Do nothing 243 | break; 244 | } 245 | return ret; 246 | } 247 | 248 | /* get data from environmental sensor and send update on BTLE */ 249 | void update_environment_data(){ 250 | float humidity, temperature; 251 | float pressure, temperature_lps22hb; 252 | 253 | HumTemp->GetHumidity(&humidity); 254 | HumTemp->GetTemperature(&temperature); 255 | 256 | PressTemp->GetPressure(&pressure); 257 | PressTemp->GetTemperature(&temperature_lps22hb); 258 | 259 | //Update environnemental data 260 | SensorService.Temp_Update(temperature*10); 261 | SensorService.Press_Update(pressure*100); 262 | SensorService.Humidity_Update(humidity*10); 263 | } 264 | 265 | /** 266 | * Update the motion data on BLE. This depends of user action in front of vl53l0x 267 | * sensor. 268 | * A tap will switch the axis to update and a swipe will rotate the cube 269 | * 270 | * @param AxesRaw_t* p_axes 271 | * @retval None 272 | */ 273 | void update_motion_data(AxesRaw_t* p_axes) 274 | { 275 | // change axis to update on each tap detection 276 | if(tap_detected()){ 277 | axis_to_update++; 278 | if( axis_to_update > UPDATE_AXIS_Y ) axis_to_update = UPDATE_AXIS_X; 279 | // test should be on Z axis. But for now, the application on smartphone 280 | // doesn't do anything with Z axis... 281 | switch(axis_to_update){ 282 | case UPDATE_AXIS_X: 283 | Serial.println("A swipe will now move the cube on X axis"); 284 | break; 285 | case UPDATE_AXIS_Y: 286 | Serial.println("A swipe will now move the cube on Y axis"); 287 | break; 288 | case UPDATE_AXIS_Z: 289 | Serial.println("A swipe will now move the cube on Z axis"); 290 | break; 291 | } 292 | } 293 | 294 | if(swipe_detected()){ 295 | count_swipe = 20; // arbitrary value in order to have a cube moving for a certain time. 296 | } 297 | 298 | if(count_swipe > 0){ 299 | switch(axis_to_update){ 300 | case UPDATE_AXIS_X: 301 | p_axes->AXIS_X += 100; // arbitrary value to move the cube 302 | break; 303 | case UPDATE_AXIS_Y: 304 | p_axes->AXIS_Y += 100; // arbitrary value to move the cube 305 | break; 306 | case UPDATE_AXIS_Z: 307 | p_axes->AXIS_Z += 100; // arbitrary value to move the cube 308 | break; 309 | } 310 | count_swipe--; 311 | SensorService.Acc_Update(p_axes); 312 | } 313 | } 314 | 315 | /*************************************************************************************** 316 | * Arduino standard functions 317 | ***************************************************************************************/ 318 | void setup() { 319 | int ret; 320 | 321 | Serial.begin(9600); 322 | 323 | Serial.println(""); 324 | Serial.println("*****************************************************************************************"); 325 | Serial.println("Demo for STMicroelectronics Disco IoT L475 board"); 326 | Serial.println(""); 327 | Serial.println("Download and install the BlueNRG application from STMicroelectronics on your smartphone, "); 328 | Serial.println("activate BLE and check the different tabs of the app."); 329 | Serial.println(""); 330 | Serial.println("Swipe and tap in front of vl53l0x sensor to move the cube."); 331 | Serial.println("*****************************************************************************************"); 332 | Serial.println(""); 333 | 334 | count_swipe = 0; 335 | axis_to_update = UPDATE_AXIS_X; 336 | axes_data.AXIS_X = 0; 337 | axes_data.AXIS_Y = 0; 338 | axes_data.AXIS_Z = 0; 339 | 340 | /* Configure the User Button in GPIO Mode */ 341 | pinMode(USER_BTN, INPUT); 342 | 343 | // Initialize I2C bus. 344 | dev_i2c = new TwoWire(I2C2_SDA, I2C2_SCL); 345 | dev_i2c->begin(); 346 | 347 | // Initlialize components. 348 | HumTemp = new HTS221Sensor (dev_i2c); 349 | HumTemp->begin(); 350 | HumTemp->Enable(); 351 | 352 | PressTemp = new LPS22HBSensor(dev_i2c); 353 | PressTemp->begin(); 354 | PressTemp->Enable(); 355 | 356 | sensor_vl53l0x = new VL53L0X(dev_i2c, PC6); 357 | sensor_vl53l0x->begin(); 358 | sensor_vl53l0x->VL53L0X_Off(); 359 | ret = sensor_vl53l0x->InitSensor(0x10); 360 | if(ret) { 361 | Serial.println("Init sensor_vl53l0x failed..."); 362 | while(1); 363 | } 364 | 365 | // Initialize gesture libraries. 366 | tof_gestures_initSWIPE_1(&gestureSwipeData); 367 | tof_gestures_initTAP_1(&gestureTapData); 368 | SetupSingleShot(); 369 | 370 | // Initialize BTLE part 371 | if(BTLE.begin() == SPBTLERF_ERROR){ 372 | Serial.println("Bluetooth module configuration error!"); 373 | while(1); 374 | } 375 | 376 | if(SensorService.begin(name, SERVER_BDADDR)){ 377 | Serial.println("Sensor service configuration error!"); 378 | while(1); 379 | } 380 | 381 | ret = SensorService.Add_Acc_Service(); 382 | if(ret == BLE_STATUS_SUCCESS) 383 | Serial.println("Acc service added successfully."); 384 | else 385 | Serial.println("Error while adding Acc service."); 386 | 387 | ret = SensorService.Add_Environmental_Sensor_Service(); 388 | if(ret == BLE_STATUS_SUCCESS) 389 | Serial.println("Environmental Sensor service added successfully."); 390 | else 391 | Serial.println("Error while adding Environmental Sensor service."); 392 | 393 | /* Instantiate Timer Service with two characteristics: 394 | * - seconds characteristic (Readable only) 395 | * - minutes characteristics (Readable and Notifiable ) 396 | */ 397 | ret = SensorService.Add_Time_Service(); 398 | if(ret == BLE_STATUS_SUCCESS) 399 | Serial.println("Time service added successfully."); 400 | else 401 | Serial.println("Error while adding Time service."); 402 | } 403 | 404 | 405 | void loop() { 406 | 407 | BTLE.update(); 408 | 409 | if(SensorService.isConnected() == TRUE) 410 | { 411 | //Update accelerometer values 412 | update_motion_data(&axes_data); 413 | 414 | //Update time 415 | SensorService.Update_Time_Characteristics(); 416 | 417 | if((millis() - previousSecond) >= 1000) 418 | { 419 | update_environment_data(); 420 | previousSecond = millis(); 421 | } 422 | } 423 | else 424 | { 425 | //Keep the Bluetooth module in discoverable mode 426 | SensorService.setConnectable(); 427 | 428 | if(swipe_detected() || tap_detected()){ 429 | Serial.println("Enable the BLE and launch BlueNRG application on your smartphone..."); 430 | } 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /examples/Boards/STM32L475VG-DISCOVERY-IOT/WiFi_MQTT_Adafruit.io/README.md: -------------------------------------------------------------------------------- 1 | # WiFi_MQTT_Adafruit.io 2 | 3 | This example demonstrates the capabilities of the [PubSubClient](https://github.com/knolleary/pubsubclient) library in combination 4 | with the [B-L475E-IOT01A](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html) board to publish on https://io.adafruit.com broker 5 | 6 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/overview 7 | 8 | # Dependencies 9 | 10 | Install the following libraries using the Arduino IDE: **_Sketch -> Include Library -> Manage Libraries_** and search: 11 | 12 | * [PubSubClient](https://github.com/knolleary/pubsubclient): Arduino Client for MQTT. 13 | * [STM32duino ISM43362-M3G-L44](https://github.com/stm32duino/WiFi-ISM43362-M3G-L44): WiFi library for the [B-L475E-IOT01A](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html) board. 14 | * [STM32duino HTS221](https://github.com/stm32duino/HTS221): to support the HTS221 capacitive digital sensor for relative humidity and temperature 15 | 16 | # Adafruit IO Dashboard. 17 | 18 | You will need to create some feeds in your Adafruit IO Dashboard. 19 | 20 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/getting-started-on-adafruit-io 21 | 22 | to know how register and create your Adafruit IO dashboard and feeds: 23 | * hello: Text block 24 | * onoff: Toggle block 25 | * temp: Stream block 26 | * hum: Gauge block 27 | 28 | A screenshot of the dashboard: 29 | [Dashboard Adafruit](/img/dashboard_adafruit.png) 30 | 31 | It connects to the Adafruit IO's MQTT server (a.k.a broker) server then: 32 | * publishes announcement "_Hi, I'm STM32 user!_" to the topic `AIO_USERNAME"/feeds/hello"` 33 | * subscribes to the topic `AIO_USERNAME"/feeds/onoff"`, switching `LED_BUILTIN` state 34 | * publishes temperature and humidity from the HTS221 sensor to the topic 35 | `AIO_USERNAME"/feeds/temp"` and `AIO_USERNAME"/feeds/hum"` every 10 seconds 36 | -------------------------------------------------------------------------------- /examples/Boards/STM32L475VG-DISCOVERY-IOT/WiFi_MQTT_Adafruit.io/WiFi_MQTT_Adafruit.io.ino: -------------------------------------------------------------------------------- 1 | /* 2 | B-L475E-IOT01A MQTT example to publish on https://io.adafruit.com broker 3 | 4 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/overview 5 | 6 | This sketch demonstrates the capabilities of the pubsub library in combination 7 | with the B-L475E-IOT01A board. 8 | 9 | It will use several components of the board and you need to install corresponding libraries : 10 | - WiFi (ISM43362-M3G-L44) : https://github.com/stm32duino/WiFi-ISM43362-M3G-L44 11 | - Temperature and humidity sensor (HTS221) : https://github.com/stm32duino/HTS221 12 | - Arduino Client for MQTT: https://github.com/knolleary/pubsubclient 13 | 14 | You can find more information on this board here : 15 | http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html 16 | 17 | You will need to create some feeds in your Adafruit IO Dashboard. 18 | See https://learn.adafruit.com/mqtt-adafruit-io-and-you/getting-started-on-adafruit-io 19 | to know how register and create your Adafruit IO dashboard and feeds: 20 | - hello: Text block 21 | - onoff: Toggle block 22 | - temp: Stream block 23 | - hum: Gauge block 24 | A screenshot of the dashboard is available in the sketch directory: dashboard_adafruit.png 25 | 26 | It connects to the Adafruit IO's MQTT server (a.k.a broker) server then: 27 | - publishes announcement "Hi, I'm STM32 user!" to the topic 'AIO_USERNAME"/feeds/hello"' 28 | - subscribes to the topic AIO_USERNAME"/feeds/onoff"', switching LED_BUILTIN state 29 | - publishes temperature and humidity from the HTS221 sensor to the topic 30 | 'AIO_USERNAME"/feeds/temp"' and 'AIO_USERNAME"/feeds/hum"' every 10 seconds 31 | 32 | It will reconnect to the server if the connection is lost using a blocking 33 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 34 | achieve the same result without blocking the main loop. 35 | 36 | */ 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // Update these with values suitable for your network. 43 | char ssid[] = "......."; 44 | const char* password = "........"; 45 | 46 | // Adafruit.io Setup 47 | #define AIO_SERVER "io.adafruit.com" 48 | #define AIO_SERVERPORT 1883 49 | #define AIO_USERNAME "......" 50 | #define AIO_KEY "........" 51 | 52 | // WiFi module setup 53 | SPIClass SPI_3(PC12, PC11, PC10); 54 | WiFiClass WiFi(&SPI_3, PE0, PE1, PE8, PB13); 55 | WiFiClient STClient; 56 | int status = WL_IDLE_STATUS; // the Wifi radio's status 57 | 58 | // i2c sensors 59 | HTS221Sensor *HumTemp; 60 | 61 | TwoWire *dev_i2c; 62 | #define I2C2_SCL PB10 63 | #define I2C2_SDA PB11 64 | 65 | 66 | PubSubClient client(STClient); 67 | long lastMsg = 0; 68 | char msg[8]; 69 | 70 | void setup() { 71 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 72 | Serial.begin(115200); 73 | setup_wifi(); 74 | client.setServer(AIO_SERVER, AIO_SERVERPORT); 75 | client.setCallback(callback); 76 | 77 | // Initialize I2C bus. 78 | dev_i2c = new TwoWire(I2C2_SDA, I2C2_SCL); 79 | dev_i2c->begin(); 80 | 81 | // Initlialize components. 82 | HumTemp = new HTS221Sensor (dev_i2c); 83 | HumTemp->begin(); 84 | HumTemp->Enable(); 85 | } 86 | 87 | void setup_wifi() { 88 | 89 | delay(10); 90 | 91 | // Initialize the WiFi module: 92 | if (WiFi.status() == WL_NO_SHIELD) { 93 | Serial.println("WiFi module not detected"); 94 | // don't continue: 95 | while (true); 96 | } 97 | 98 | // Print firmware version: 99 | String fv = WiFi.firmwareVersion(); 100 | Serial.print("Firmware version: "); 101 | Serial.println(fv); 102 | 103 | if (fv != "C3.5.2.3.BETA9") { 104 | Serial.println("Please upgrade the firmware"); 105 | } 106 | 107 | // Attempt to connect to Wifi network: 108 | Serial.print("Attempting to connect to network: "); 109 | Serial.println(ssid); 110 | while (status != WL_CONNECTED) { 111 | Serial.print("."); 112 | // Connect to network: 113 | status = WiFi.begin(ssid, password); 114 | // Wait 10 seconds for connection: 115 | delay(10000); 116 | } 117 | 118 | Serial.println(); 119 | Serial.println("WiFi connected"); 120 | Serial.println("IP address: "); 121 | Serial.println(WiFi.localIP()); 122 | } 123 | 124 | void callback(char* topic, byte* payload, unsigned int length) { 125 | 126 | #if 0 127 | Serial.print("Message arrived ["); 128 | Serial.print(topic); 129 | Serial.print("] "); 130 | for (unsigned int i = 0; i < length; i++) { 131 | Serial.print((char)payload[i]); 132 | } 133 | Serial.println(); 134 | #else 135 | UNUSED(topic); 136 | #endif 137 | if (length > 1) { 138 | // Switch on/off the LED (payload messages can be 'ON' or 'OFF') 139 | if ((char)payload[1] == 'N') { 140 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on 141 | } else { 142 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED off 143 | } 144 | } 145 | } 146 | 147 | void reconnect() { 148 | // Loop until we're reconnected 149 | while (!client.connected()) { 150 | Serial.print("Attempting MQTT connection..."); 151 | // Attempt to connect 152 | // Note - the default maximum packet size is 128 bytes. If the 153 | // combined length of clientId, username and password exceed this, 154 | // you will need to increase the value of MQTT_MAX_PACKET_SIZE in 155 | // PubSubClient.h 156 | if (client.connect("STM32Client", AIO_USERNAME, AIO_KEY)) { 157 | Serial.println("connected"); 158 | // Once connected, publish an announcement... 159 | client.publish(AIO_USERNAME"/feeds/hello", "Hi, I'm STM32 user!"); 160 | // ... and resubscribe 161 | client.subscribe(AIO_USERNAME"/feeds/onoff"); 162 | } else { 163 | Serial.print("failed, rc="); 164 | Serial.print(client.state()); 165 | Serial.println(" try again in 5 seconds"); 166 | // Wait 5 seconds before retrying 167 | delay(5000); 168 | } 169 | } 170 | } 171 | 172 | void loop() { 173 | float temperature, humidity; 174 | if (!client.connected()) { 175 | reconnect(); 176 | } 177 | client.loop(); 178 | 179 | long now = millis(); 180 | if (now - lastMsg > 10000) { 181 | lastMsg = now; 182 | HumTemp->GetTemperature(&temperature); 183 | dtostrf(temperature, 2, 2, msg); 184 | Serial.print("Publish temperature "); 185 | Serial.println(msg); 186 | client.publish(AIO_USERNAME"/feeds/temp", msg); 187 | 188 | HumTemp->GetHumidity(&humidity); 189 | snprintf (msg, 8, "%u", (unsigned int)humidity); 190 | Serial.print("Publish humidity "); 191 | Serial.println(msg); 192 | client.publish(AIO_USERNAME"/feeds/hum", msg); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /examples/Communication/MQTT/MQTTClient/Hello_stm32/Hello_stm32.ino: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014, 2015 IBM Corp. 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Eclipse Distribution License v1.0 which accompany this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * and the Eclipse Distribution License is available at 11 | * http://www.eclipse.org/org/documents/edl-v10.php. 12 | * 13 | * Contributors: 14 | * Ian Craggs - initial contribution 15 | * Benjamin Cabe - adapt to IPStack, and add Yun instructions 16 | * Ian Craggs - remove sprintfs to reduce sketch size 17 | * 18 | * Modified by Frederic Pillon to use the STM32 Ethernet Library 19 | * Only includes have changed: 20 | * #include 21 | * #include 22 | * Replaced by: 23 | * #include 24 | * #include 25 | *******************************************************************************/ 26 | 27 | #define WARN Serial.println 28 | 29 | #define MQTTCLIENT_QOS2 1 30 | 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | int arrivedcount = 0; 39 | 40 | void messageArrived(MQTT::MessageData& md) 41 | { 42 | MQTT::Message &message = md.message; 43 | 44 | Serial.print("Message "); 45 | Serial.print(++arrivedcount); 46 | Serial.print(" arrived: qos "); 47 | Serial.print(message.qos); 48 | Serial.print(", retained "); 49 | Serial.print(message.retained); 50 | Serial.print(", dup "); 51 | Serial.print(message.dup); 52 | Serial.print(", packetid "); 53 | Serial.println(message.id); 54 | Serial.print("Payload "); 55 | Serial.println((char*)message.payload); 56 | } 57 | 58 | 59 | EthernetClient c; // replace by a YunClient if running on a Yun 60 | IPStack ipstack(c); 61 | MQTT::Client client = MQTT::Client(ipstack); 62 | 63 | byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; // replace with your device's MAC 64 | const char* topic = "arduino-sample"; 65 | 66 | void connect() 67 | { 68 | char hostname[] = "iot.eclipse.org"; 69 | int port = 1883; 70 | 71 | Serial.print("Connecting to "); 72 | Serial.print(hostname); 73 | Serial.print(":"); 74 | Serial.println(port); 75 | 76 | int rc = ipstack.connect(hostname, port); 77 | if (rc != 1) 78 | { 79 | Serial.print("rc from TCP connect is "); 80 | Serial.println(rc); 81 | } 82 | 83 | Serial.println("MQTT connecting"); 84 | MQTTPacket_connectData data = MQTTPacket_connectData_initializer; 85 | data.MQTTVersion = 3; 86 | data.clientID.cstring = (char*)"arduino-sample"; 87 | rc = client.connect(data); 88 | if (rc != 0) 89 | { 90 | Serial.print("rc from MQTT connect is "); 91 | Serial.println(rc); 92 | } 93 | Serial.println("MQTT connected"); 94 | 95 | rc = client.subscribe(topic, MQTT::QOS2, messageArrived); 96 | if (rc != 0) 97 | { 98 | Serial.print("rc from MQTT subscribe is "); 99 | Serial.println(rc); 100 | } 101 | Serial.println("MQTT subscribed"); 102 | } 103 | 104 | void setup() 105 | { 106 | Serial.begin(9600); 107 | Ethernet.begin(mac); 108 | Serial.println("MQTT Hello example"); 109 | connect(); 110 | } 111 | 112 | MQTT::Message message; 113 | 114 | void loop() 115 | { 116 | if (!client.isConnected()) 117 | connect(); 118 | 119 | arrivedcount = 0; 120 | 121 | // Send and receive QoS 0 message 122 | char buf[100]; 123 | strcpy(buf, "Hello World! QoS 0 message"); 124 | message.qos = MQTT::QOS0; 125 | message.retained = false; 126 | message.dup = false; 127 | message.payload = (void*)buf; 128 | message.payloadlen = strlen(buf)+1; 129 | int rc = client.publish(topic, message); 130 | while (arrivedcount == 0) 131 | { 132 | Serial.println("Waiting for QoS 0 message"); 133 | client.yield(1000); 134 | } 135 | 136 | // Send and receive QoS 1 message 137 | strcpy(buf, "Hello World! QoS 1 message"); 138 | message.qos = MQTT::QOS1; 139 | message.payloadlen = strlen(buf)+1; 140 | rc = client.publish(topic, message); 141 | while (arrivedcount == 1) 142 | { 143 | Serial.println("Waiting for QoS 1 message"); 144 | client.yield(1000); 145 | } 146 | 147 | // Send and receive QoS 2 message 148 | strcpy(buf, "Hello World! QoS 2 message"); 149 | message.qos = MQTT::QOS2; 150 | message.payloadlen = strlen(buf)+1; 151 | rc = client.publish(topic, message); 152 | while (arrivedcount == 2) 153 | { 154 | Serial.println("Waiting for QoS 2 message"); 155 | client.yield(1000); 156 | } 157 | delay(2000); 158 | } 159 | -------------------------------------------------------------------------------- /examples/Communication/MQTT/MQTTClient/README.md: -------------------------------------------------------------------------------- 1 | # Paho MQTT C client 2 | 3 | Required to install prebuilt Arduino port of MQTTClient. 4 | 5 | See http://www.eclipse.org/paho/clients/c/embedded/ 6 | 7 | Download the prebuilt Arduino port of MQTTClient and in the Arduino IDE use 8 | **_Sketch -> Include Library -> Add .ZIP Library..._** with the downloaded client zip file. 9 | 10 | # Examples 11 | 12 | ## Hello_stm32 (original _name Hello_) 13 | This is the basic example provided with the MQTTClient library. 14 | It has been modified to use the [STM32 Ethernet](https://github.com/stm32duino/STM32Ethernet) library. 15 | 16 | Only includes have changed: 17 | ``` 18 | #include 19 | #include 20 | ``` 21 | Replaced by: 22 | ``` 23 | #include 24 | #include 25 | ``` 26 | -------------------------------------------------------------------------------- /examples/Communication/MQTT/PubSubClient/README.md: -------------------------------------------------------------------------------- 1 | # PubSubClient 2 | 3 | This library provides a client for doing simple publish/subscribe messaging with a server that supports MQTT. 4 | 5 | https://github.com/knolleary/pubsubclient 6 | 7 | # Dependencies 8 | 9 | Install the following libraries using the Arduino IDE: **_Sketch -> Include Library -> Manage Libraries_** and search: 10 | 11 | * [PubSubClient](https://github.com/knolleary/pubsubclient): Arduino Client for MQTT. 12 | * [STM32duino ISM43362-M3G-L44](https://github.com/stm32duino/WiFi-ISM43362-M3G-L44): WiFi library for the B-L475E-IOT01A board. 13 | * [STM32 Ethernet](https://github.com/stm32duino/STM32Ethernet): Ethernet library for STM32 based board with on-board Ethernet connector. 14 | 15 | # Examples 16 | 17 | ## mqtt_B-L475E-IOT01A 18 | This example is based on the mqtt_esp8266 provided with PubSubClient library. 19 | It has been modified to use the [STM32duino ISM43362-M3G-L44](https://github.com/stm32duino/WiFi-ISM43362-M3G-L44) WiFi library with [B-L475E-IOT01A](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html) board 20 | 21 | ## mqtt_STM32Ethernet 22 | This example is based on the mqtt_basic provided with PubSubClient library. 23 | It has been modified to use the [STM32 Ethernet](https://github.com/stm32duino/STM32Ethernet) Ethernet library with a STM32 based board 24 | with on-board Ethernet connector. 25 | -------------------------------------------------------------------------------- /examples/Communication/MQTT/PubSubClient/mqtt_B-L475E-IOT01A/mqtt_B-L475E-IOT01A.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic B-L475E-IOT01A MQTT example 3 | 4 | This example is based on the mqtt_esp8266 provided with PubSubClient library. 5 | 6 | This sketch demonstrates the capabilities of the pubsub library in combination 7 | with the B-L475E-IOT01A board. 8 | 9 | It connects to an MQTT server then: 10 | - publishes "hello world" to the topic "outTopic" every two seconds 11 | - subscribes to the topic "inTopic", printing out any messages 12 | it receives. NB - it assumes the received payloads are strings not binary 13 | - If the first character of the topic "inTopic" is an 1, switch ON the LED_BUILTIN Led, 14 | else switch it off 15 | 16 | It will reconnect to the server if the connection is lost using a blocking 17 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 18 | achieve the same result without blocking the main loop. 19 | */ 20 | #include 21 | #include 22 | #include 23 | 24 | // Update these with values suitable for your network. 25 | char ssid[] = "......."; 26 | const char* password = "......."; 27 | const char* mqtt_server = "broker.mqtt-dashboard.com"; 28 | 29 | SPIClass SPI_3(PC12, PC11, PC10); 30 | WiFiClass WiFi(&SPI_3, PE0, PE1, PE8, PB13); 31 | WiFiClient STClient; 32 | int status = WL_IDLE_STATUS; // the Wifi radio's status 33 | 34 | PubSubClient client(STClient); 35 | long lastMsg = 0; 36 | char msg[50]; 37 | long value = 0; 38 | 39 | void setup() { 40 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 41 | Serial.begin(115200); 42 | setup_wifi(); 43 | client.setServer(mqtt_server, 1883); 44 | client.setCallback(callback); 45 | } 46 | 47 | void setup_wifi() { 48 | 49 | delay(10); 50 | 51 | // initialize the WiFi module: 52 | if (WiFi.status() == WL_NO_SHIELD) { 53 | Serial.println("WiFi module not detected"); 54 | // don't continue: 55 | while (true); 56 | } 57 | 58 | // print firmware version: 59 | String fv = WiFi.firmwareVersion(); 60 | Serial.print("Firmware version: "); 61 | Serial.println(fv); 62 | 63 | if (fv != "C3.5.2.3.BETA9") { 64 | Serial.println("Please upgrade the firmware"); 65 | } 66 | 67 | // attempt to connect to Wifi network: 68 | Serial.print("Attempting to connect to network: "); 69 | Serial.println(ssid); 70 | while (status != WL_CONNECTED) { 71 | Serial.print("."); 72 | // Connect to WPA2 network: 73 | status = WiFi.begin(ssid, password); 74 | if (status != WL_CONNECTED) { 75 | // Connect to WPA (TKIP) network: 76 | status = WiFi.begin(ssid, password, ES_WIFI_SEC_WPA); 77 | } 78 | // wait 10 seconds for connection: 79 | delay(10000); 80 | } 81 | 82 | Serial.println(); 83 | Serial.println("WiFi connected"); 84 | Serial.println("IP address: "); 85 | Serial.println(WiFi.localIP()); 86 | } 87 | 88 | void callback(char* topic, byte* payload, unsigned int length) { 89 | Serial.print("Message arrived ["); 90 | Serial.print(topic); 91 | Serial.print("] "); 92 | for (unsigned int i = 0; i < length; i++) { 93 | Serial.print((char)payload[i]); 94 | } 95 | Serial.println(); 96 | 97 | // Switch on the LED if an 1 was received as first character 98 | if ((char)payload[0] == '1') { 99 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on 100 | } else { 101 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED off 102 | } 103 | } 104 | 105 | void reconnect() { 106 | // Loop until we're reconnected 107 | while (!client.connected()) { 108 | Serial.print("Attempting MQTT connection..."); 109 | // Attempt to connect 110 | if (client.connect("B-L475E-IOT01AClient")) { 111 | Serial.println("connected"); 112 | // Once connected, publish an announcement... 113 | client.publish("outTopic", "hello world"); 114 | // ... and resubscribe 115 | client.subscribe("inTopic"); 116 | } else { 117 | Serial.print("failed, rc="); 118 | Serial.print(client.state()); 119 | Serial.println(" try again in 5 seconds"); 120 | // Wait 5 seconds before retrying 121 | delay(5000); 122 | } 123 | } 124 | } 125 | void loop() { 126 | 127 | if (!client.connected()) { 128 | reconnect(); 129 | } 130 | client.loop(); 131 | 132 | long now = millis(); 133 | if (now - lastMsg > 2000) { 134 | lastMsg = now; 135 | ++value; 136 | snprintf (msg, 50, "hello world #%ld", value); 137 | Serial.print("Publish message: "); 138 | Serial.println(msg); 139 | client.publish("outTopic", msg); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /examples/Communication/MQTT/PubSubClient/mqtt_STM32Ethernet/mqtt_STM32Ethernet.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic STM32 Ethernet MQTT example 3 | 4 | This sketch demonstrates the basic capabilities of the library. 5 | It connects to an MQTT server then: 6 | - publishes "hello world" to the topic "outTopic" every two seconds 7 | - subscribes to the topic "inTopic", printing out any messages 8 | it receives. NB - it assumes the received payloads are strings not binary 9 | 10 | It will reconnect to the server if the connection is lost using a blocking 11 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 12 | achieve the same result without blocking the main loop. 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | // Update these with values suitable for your network. 21 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 22 | // Set the static IP address to use if the DHCP fails to assign 23 | IPAddress ip(192, 168, 0, 177); 24 | // if you don't want to use DNS (and reduce your sketch size) 25 | // use the numeric IP instead of the name for the server: 26 | //IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) 27 | char server[] = "broker.mqtt-dashboard.com"; // name address for mqtt broker (using DNS) 28 | long lastMsg = 0; 29 | char msg[50]; 30 | long value = 0; 31 | 32 | void callback(char* topic, byte* payload, unsigned int length) { 33 | Serial.print("Message arrived ["); 34 | Serial.print(topic); 35 | Serial.print("] "); 36 | for (unsigned int i=0;i 2000) { 93 | lastMsg = now; 94 | ++value; 95 | snprintf (msg, 50, "hello world #%ld", value); 96 | Serial.print("Publish message: "); 97 | Serial.println(msg); 98 | client.publish("outTopic", msg); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/STLTest/STLTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | STLTest 3 | 4 | Test abs/min/max/round called from C or C++ 5 | 6 | Creation 10 Oct 2017 7 | by Frederic Pillon 8 | 9 | This example code is in the public domain. 10 | */ 11 | 12 | #include "test_stl.h" 13 | static int32_t count_pressed = 0; 14 | static int32_t random_val = 0; 15 | 16 | // Check if a default user button is defined 17 | // If not then define it to pin 2, user can set an other pin. 18 | // Button have to be wired on this pin 19 | #ifndef USER_BTN 20 | #define USER_BTN 2 21 | #endif 22 | int pushButton = USER_BTN; 23 | 24 | // the setup routine runs once when you press reset: 25 | void setup() { 26 | // initialize serial communication at 115200 bits per second: 27 | Serial.begin(115200); 28 | // make the pushbutton's pin an input: 29 | pinMode(pushButton, INPUT); 30 | // if analog input pin 0 is unconnected, random analog 31 | // noise will cause the call to randomSeed() to generate 32 | // different seed numbers each time the sketch runs. 33 | // randomSeed() will then shuffle the random function. 34 | randomSeed(analogRead(0)); 35 | } 36 | 37 | // the loop routine runs over and over again forever: 38 | void loop() { 39 | // read the input pin: 40 | int buttonState = digitalRead(pushButton); 41 | random_val = random(300); 42 | if (buttonState == LOW) 43 | { 44 | count_pressed++; 45 | } 46 | 47 | Serial.print("count pressed: "); 48 | Serial.print(count_pressed); 49 | Serial.print("\trandom: "); 50 | Serial.println(random_val); 51 | 52 | Serial.print("C++\tmin: "); 53 | Serial.print(min(random_val,count_pressed)); 54 | Serial.print("\tmax: "); 55 | Serial.print(max(random_val,count_pressed)); 56 | Serial.print("\tabs: "); 57 | Serial.print(abs(count_pressed)); 58 | Serial.print("\tround (count_pressed/random_val): "); 59 | Serial.println(round(count_pressed/random_val)); 60 | 61 | Serial.print("C\tmin: "); 62 | Serial.print(test_c(random_val,count_pressed, MIN)); 63 | Serial.print("\tmax: "); 64 | Serial.print(test_c(random_val,count_pressed, MAX)); 65 | Serial.print("\tabs: "); 66 | Serial.print(test_c(count_pressed, 0, ABS)); 67 | Serial.print("\tround (count_pressed/random_val) is "); 68 | Serial.println(test_c(count_pressed, random_val, ROUND)); 69 | 70 | Serial.println(); 71 | delay(100); // delay in between reads for stability 72 | } 73 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/STLTest/test_stl.c: -------------------------------------------------------------------------------- 1 | #include "test_stl.h" 2 | #include "Arduino.h" 3 | 4 | int test_c(int a, int b, test t) 5 | { 6 | switch(t) { 7 | default: 8 | case ABS: 9 | return abs(a); 10 | break; 11 | case MIN: 12 | return min(a,b); 13 | break; 14 | case MAX: 15 | return max(a,b); 16 | break; 17 | case ROUND: 18 | return round(a/b); 19 | break; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/STLTest/test_stl.h: -------------------------------------------------------------------------------- 1 | #ifndef _STLTEST_H_ 2 | #define _STLTEST_H_ 3 | 4 | typedef enum _test { 5 | ABS, 6 | MIN, 7 | MAX, 8 | ROUND 9 | } test; 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | int test_c(int a, int b, test t); 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | 20 | 21 | #endif /*_STLTEST_H_*/ 22 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/Tests_basic_functions/Test_IO.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test some advanced I/O functions 3 | */ 4 | #ifdef TIMER_TONE 5 | /* 6 | * Variable for advanced I/O test 7 | */ 8 | int modeWR = 0; 9 | volatile int clknb = 0; 10 | volatile int data = 0; 11 | int clkOut = 2; 12 | int dataOut = 3; 13 | int clkIn = 4; 14 | int dataIn = 5; 15 | 16 | void test_IO(void) 17 | { 18 | bool validate = true; 19 | int tmp = 0; 20 | int freq_test = 1000; 21 | 22 | Serial.println(); 23 | Serial.println("----------------------------------------"); 24 | Serial.println("TEST ADVANCED I/O"); 25 | Serial.println("Connect D2 with D4 and D3 with D5. Then press ENTER."); 26 | while (message((char*)"\n") == false) {yield();} 27 | 28 | pinMode(clkOut, OUTPUT); 29 | pinMode(dataOut, OUTPUT); 30 | pinMode(clkIn, INPUT); 31 | pinMode(dataIn, INPUT); 32 | 33 | tone(clkOut,freq_test); 34 | while(digitalRead(clkIn) == HIGH){yield();} 35 | if(digitalRead(clkIn) == LOW) { 36 | tmp = pulseIn(clkIn, HIGH); 37 | } 38 | noTone(clkOut); 39 | pinMode(clkOut, OUTPUT); 40 | 41 | float freq_period_us = 1.0/(float)freq_test; 42 | tmp -= freq_period_us*1000000/2; 43 | tmp = abs(tmp); 44 | 45 | //error = +/-1% 46 | if(tmp > 10) {validate = false;} 47 | 48 | digitalWrite(clkOut, LOW); 49 | digitalWrite(dataOut, LOW); 50 | 51 | attachInterrupt(clkIn, test_IO_IT, RISING); 52 | 53 | clknb = 0; 54 | data = 0; 55 | modeWR = 0; 56 | shiftOut(dataOut, clkOut, LSBFIRST, 0xE2); 57 | if(data != 0xE2) {validate = false;} 58 | digitalWrite(clkOut, LOW); 59 | digitalWrite(dataOut, LOW); 60 | pinMode(dataIn, OUTPUT); 61 | pinMode(dataOut, INPUT); 62 | data = 0xD7; 63 | clknb = 0; 64 | 65 | modeWR = 1; 66 | data = shiftIn(dataOut, clkOut, LSBFIRST); 67 | if(data != 0xD7) {validate = false;} 68 | 69 | detachInterrupt(clkIn); 70 | 71 | printResult(validate); 72 | } 73 | 74 | void test_IO_IT(void) 75 | { 76 | if(modeWR == 0) { 77 | data |= digitalRead(dataIn) << clknb; 78 | clknb++; 79 | } else { 80 | int tmp = bitRead(data, clknb); 81 | digitalWrite(dataIn, tmp); 82 | clknb++; 83 | } 84 | } 85 | #endif 86 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/Tests_basic_functions/Test_bytes.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test some bytes functions 3 | */ 4 | void test_bytes(void) 5 | { 6 | bool validate = true; 7 | 8 | Serial.println(); 9 | Serial.println("----------------------------------------"); 10 | Serial.println("TEST BIT & BYTES FUNCTIONS"); 11 | 12 | int val = 0x2563; 13 | 14 | if(lowByte(val) != 0x63) {validate = false;} 15 | if(highByte(val) != 0x25) {validate = false;} 16 | if(bitRead(val, 5) != 1) {validate = false;} 17 | bitWrite(val, 3, 1); 18 | if(val != 0x256B) {validate = false;} 19 | bitSet(val, 12); 20 | if(val != 0x356B) {validate = false;} 21 | bitClear(val, 8); 22 | if(val != 0x346B) {validate = false;} 23 | val = bit(2) + bit(4); 24 | if(val != 0x14) {validate = false;} 25 | 26 | printResult(validate); 27 | } 28 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/Tests_basic_functions/Test_math.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test some math and trigo functions 3 | */ 4 | void test_math(void) 5 | { 6 | bool validate = true; 7 | 8 | Serial.println(); 9 | Serial.println("----------------------------------------"); 10 | Serial.println("TEST MATH & TRIGONOMETRY FUNCTIONS"); 11 | 12 | if(min(1512,25) != 25) {validate = false;} 13 | if(max(1512,25) != 1512) {validate = false;} 14 | if((abs(-12) != 12) && (abs(52) != 52)) {validate = false;} 15 | if((round(13.99) != 13) && (round(13.01) != 13)) {validate = false;} 16 | if(pow(2,3) != 8) {validate = false;} 17 | if(sqrt(4) != 2) {validate = false;} 18 | if((sin(PI/2) - 1.0) > 0.00001) {validate = false;} 19 | if((cos(0) - 1.0) > 0.00001) {validate = false;} 20 | if((tan(PI/4) - 1.0) > 0.00001) {validate = false;} 21 | 22 | printResult(validate); 23 | } 24 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/Tests_basic_functions/Test_string.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test some the string functions 3 | */ 4 | void test_string(void) 5 | { 6 | int validate = true; 7 | 8 | Serial.println(); 9 | Serial.println("----------------------------------------"); 10 | Serial.println("TEST STRING FUNCTIONS"); 11 | 12 | String str = "hello world!"; 13 | String strTmp = String("helln"); 14 | 15 | if(strTmp.compareTo(str) != 0) { 16 | strTmp.concat(" world!"); 17 | } else {validate = false;} 18 | 19 | strTmp.remove(0,6); 20 | if(strTmp.equals("world!") == false) {validate = false;} 21 | 22 | char cbuf[13]; 23 | byte bbuf[13]; 24 | str.getBytes(bbuf,13); 25 | str.toCharArray(cbuf,13); 26 | if(strcmp((const char *)bbuf,str.c_str()) != 0) {validate = false;} 27 | if(strcmp((const char *)cbuf,str.c_str()) != 0) {validate = false;} 28 | 29 | strTmp = "12.34"; 30 | if(strTmp.toFloat()-12.34 >= 0.00001) {validate = false;} 31 | 32 | char sout[256]=""; 33 | if(strcmp(dtostrf(1.23, 7, 2, sout), " 1.23") != 0) {validate = false;} 34 | if(strcmp(dtostrf(1.899, 2, 2, sout), "1.90") != 0) {validate = false;} 35 | if(strcmp(dtostrf(-123456.78910, 127, 6, sout), 36 | " -123456.789100" 37 | ) != 0) {validate = false;} 38 | if(strcmp(dtostrf(-123456.78910, 128, 6, sout), 39 | "-123456.789100 " 40 | ) != 0) {validate = false;} 41 | 42 | printResult(validate); 43 | } 44 | -------------------------------------------------------------------------------- /examples/NonReg/Basics/Tests_basic_functions/Tests_basic_functions.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This sketch test several of the Arduino standard functions which 3 | * are not tested in the example sketches. 4 | * 5 | * !!! The human action is sometimes required! 6 | * 7 | * Created by Wi6Labs www.wi6labs.com 8 | * Modified by Frederic Pillon 9 | */ 10 | 11 | void setup() { 12 | // put your setup code here, to run once: 13 | Serial.begin(9600); 14 | 15 | list_test(); 16 | } 17 | 18 | void list_test(void) 19 | { 20 | Serial.println(); 21 | Serial.println("**Enter a number to select a test**"); 22 | Serial.println("1-String"); 23 | Serial.println("2-Math"); 24 | Serial.println("3-Bytes"); 25 | #ifdef TIMER_TONE 26 | Serial.println("4-Advanced I/O"); 27 | #endif 28 | } 29 | 30 | void loop() { 31 | int test = 0; 32 | 33 | while (Serial.available() > 0) { 34 | test = Serial.parseInt(); 35 | Serial.flush(); 36 | 37 | switch(test) 38 | { 39 | case 1: test_string(); break; 40 | case 2: test_math(); break; 41 | case 3: test_bytes(); break; 42 | #ifdef TIMER_TONE 43 | case 4: test_IO(); break; 44 | #endif 45 | default: break; 46 | } 47 | 48 | list_test(); 49 | } 50 | 51 | test = 0; 52 | } 53 | 54 | bool message(char *str) 55 | { 56 | if (Serial.available() > 0) { 57 | if (Serial.find(str) == true) 58 | return true; 59 | } 60 | 61 | return false; 62 | } 63 | 64 | void printResult(int validate) 65 | { 66 | if(validate == true) { 67 | Serial.println("> OK <"); 68 | } else { 69 | Serial.println(">>> FAIL <<<"); 70 | } 71 | } 72 | 73 | /*----------------------------------------------------------------------------------*/ 74 | -------------------------------------------------------------------------------- /examples/NonReg/BufferedEEPROM/BufferedEEPROM.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(DATA_EEPROM_BASE) 4 | #warning "STM32 devices have an integrated EEPROM. No buffered API available." 5 | 6 | void setup() { 7 | } 8 | 9 | void loop() { 10 | } 11 | 12 | #else 13 | /** 14 | Most STM32 devices don't have an integrated EEPROM. 15 | To emulate a EEPROM, the STM32 Arduino core emulated 16 | the operation of an EEPROM with the help of the embedded 17 | flash. 18 | 19 | Writing to a flash is very expensive operation, since a 20 | whole flash page needs to be written, even if you only 21 | want to access the flash byte-wise. 22 | 23 | The STM32 Arduino core provides a buffered access API 24 | to the emulated EEPROM. The library has allocated the 25 | buffer even if you don't use the buffered API, so 26 | it's strongly suggested to use the buffered API anyhow. 27 | */ 28 | 29 | #define DATA_LENGTH E2END 30 | 31 | void setup() { 32 | Serial.begin(115200); 33 | } 34 | 35 | void loop() { 36 | // Fill the EEPROM buffer in memory with data 37 | for (uint16_t i = 0; i < DATA_LENGTH; i++) { 38 | eeprom_buffered_write_byte(i, i % 256); 39 | } 40 | 41 | // Copy the data from the buffer to the flash 42 | eeprom_buffer_flush(); 43 | 44 | // Clear the buffer for demonstration purpose 45 | for (uint16_t i = 0; i < DATA_LENGTH; i++) { 46 | eeprom_buffered_write_byte(i, 0); 47 | } 48 | 49 | // Print the 254th byte of the current buffer (should be 0) 50 | Serial.println(eeprom_buffered_read_byte(254)); 51 | 52 | // Copy the data from the flash to the buffer 53 | eeprom_buffer_fill(); 54 | 55 | // Print the 254th byte of the current buffer (should be 254) 56 | Serial.println(eeprom_buffered_read_byte(254)); 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /examples/NonReg/CheckVariant/CheckVariant.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch check: 3 | - digital and analog pins defined in the variant 4 | - peripheral instances associated to wire (I2C), serial (UART) and SPI 5 | */ 6 | 7 | #include "utils.h" 8 | 9 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01090000) 10 | #error "This sketch is not compatible with core version prior to 2.0.0" 11 | #endif 12 | 13 | #define PORTx(pn) (char)('A' + STM_PORT(pn)) 14 | #define PINx(pn) STM_PIN(pn) 15 | 16 | #ifndef LED_BUILTIN 17 | #define LED_BUILTIN PNUM_NOT_DEFINED 18 | #endif 19 | 20 | /* 21 | Initial check of Serial to be sure we can further print on serial 22 | Returns true in case of test passed 23 | Returns false in case of test failed 24 | */ 25 | bool checkSerial(void) { 26 | bool testPassed = true; 27 | #if defined(PinMap_UART_RX) && defined(PinMap_UART_TX) 28 | USART_TypeDef *uart_rx = (USART_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SERIAL_RX), PinMap_UART_RX); 29 | USART_TypeDef *uart_tx = (USART_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SERIAL_TX), PinMap_UART_TX); 30 | if (uart_rx == NP) { 31 | /* PIN_SERIAL_RX (%d) doesn't match a valid UART peripheral */ 32 | testPassed = false; 33 | } 34 | if (uart_tx == NP) { 35 | /* PIN_SERIAL_TX doesn't match a valid UART peripheral */ 36 | testPassed = false; 37 | } 38 | if (uart_rx != uart_tx) { 39 | /* PIN_SERIAL_RX (%d) doesn't match PIN_SERIAL_TX peripheral */ 40 | testPassed = false; 41 | } 42 | #endif 43 | return testPassed; 44 | } 45 | 46 | /* 47 | Prints Pin name 48 | pname: Pin of type PinName (PY_n) 49 | asPN: true display as a PinName, false as a pin number (PYn) 50 | val: display value or not 51 | ln: carriage return or not 52 | */ 53 | void printPinName(PinName pname, bool asPN, bool val, bool ln) { 54 | Serial.print("P"); 55 | Serial.print(PORTx(pname)); 56 | if (asPN) { 57 | Serial.print("_"); 58 | } 59 | Serial.print(PINx(pname)); 60 | if (val) { 61 | Serial.print(" ("); 62 | Serial.print(asPN ? (uint32_t)pname : pinNametoDigitalPin(pname)); 63 | Serial.print(")"); 64 | } 65 | if (ln) { 66 | Serial.println(); 67 | } 68 | } 69 | 70 | void setup() { 71 | /* Check first whether Serial is valid and we can further print on Serial */ 72 | if (!checkSerial()) { 73 | uint32_t blinkDelay = 200; 74 | while (1) { 75 | /* blink led quickly and forever in case of error */ 76 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on 77 | delay(blinkDelay); 78 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off 79 | delay(blinkDelay); 80 | } 81 | } 82 | 83 | Serial.begin(115200); 84 | while (!Serial) { 85 | ; // wait for serial port to connect. Needed for native USB port only 86 | } 87 | pinMode(LED_BUILTIN, OUTPUT); 88 | } 89 | 90 | void loop() { 91 | 92 | bool testPassed = true; 93 | String testStatus; 94 | uint32_t blinkDelay; 95 | 96 | Serial.println("#####"); 97 | Serial.printf("NUM_DIGITAL_PINS = %i\n", NUM_DIGITAL_PINS); 98 | Serial.printf("NUM_ANALOG_INPUTS = %i\n", NUM_ANALOG_INPUTS); 99 | 100 | /* Run the different tests */ 101 | if (!checkDigitalPins()) { 102 | testPassed = false; 103 | } 104 | if (!checkAnalogPins()) { 105 | testPassed = false; 106 | } 107 | if (!checkIPInstance()) { 108 | testPassed = false; 109 | } 110 | 111 | /* Display test result */ 112 | if (testPassed) { 113 | testStatus = "PASSED"; 114 | blinkDelay = 1000; 115 | } else { 116 | testStatus = "FAILED"; 117 | blinkDelay = 200; 118 | } 119 | Serial.println(""); 120 | Serial.println("########################################"); 121 | Serial.printf("#### Test %s\n", testStatus.c_str()); 122 | Serial.println("########################################"); 123 | 124 | /* Blink Led forever, slowly for test passed, and quickly for test failed */ 125 | while (1) { 126 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) 127 | delay(blinkDelay); 128 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW 129 | delay(blinkDelay); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /examples/NonReg/CheckVariant/analogPinsTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Check Analog pins 3 | Return true in case of test passed 4 | Return false in case of test failed 5 | */ 6 | bool checkAnalogPins(void) { 7 | bool testPassed = true; 8 | 9 | Serial.println("#####"); 10 | Serial.println("Checking analog pins definition..."); 11 | 12 | for ( uint32_t i = 0; i < (NUM_ANALOG_INPUTS); i++) { 13 | uint8_t res = 0; 14 | // i is the index in the analogInputPin array 15 | uint32_t pinnum_array = analogInputPin[i]; 16 | uint32_t pinnum_aTD_i = analogInputToDigitalPin(i); 17 | uint32_t pinnum_aTD_Ax = analogInputToDigitalPin(A0 + i); 18 | 19 | PinName pn_dTpn_Ax = digitalPinToPinName(A0 + i); 20 | PinName pn_aTpn_Ax = analogInputToPinName(A0 + i); 21 | 22 | 23 | if ((pinnum_array != pinnum_aTD_i) || (pinnum_array != pinnum_aTD_Ax) || (pinnum_aTD_i == NC)) { 24 | res = 1; 25 | } 26 | if (!digitalpinIsAnalogInput(pinnum_array) || !digitalpinIsAnalogInput(pinnum_aTD_i) || !digitalpinIsAnalogInput(pinnum_aTD_Ax)) { 27 | res |= 2; 28 | } 29 | if ((pn_dTpn_Ax != pn_aTpn_Ax) || (pinnum_aTD_i == NC)) { 30 | res |= 4; 31 | } 32 | if (digitalPinToAnalogInput(pinnum_aTD_i) != i) { 33 | 34 | res |= 8; 35 | } 36 | 37 | if (res) { 38 | Serial.printf("A%i defined as %i with pin name: ", i, A0 + i); 39 | printPinName(pn_aTpn_Ax, true, true, false); 40 | Serial.print(" and pin number: "); 41 | printPinName(pn_aTpn_Ax, false, true, false); 42 | Serial.printf(" --> %i\n", res); 43 | Serial.printf(" --> digitalPinToAnalogInput(%i) = %i\n", pinnum_aTD_i, digitalPinToAnalogInput(pinnum_aTD_i)); 44 | testPassed = false; 45 | } 46 | } 47 | Serial.println("End check analog pins"); 48 | return testPassed; 49 | } 50 | -------------------------------------------------------------------------------- /examples/NonReg/CheckVariant/checkIPInstanceTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Checks Wire instances (I2C) 3 | Returns true in case of test passed 4 | Returns false in case of test failed 5 | */ 6 | bool checkI2CInstance(void) { 7 | bool testPassed = true; 8 | 9 | #if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) 10 | I2C_TypeDef *i2c_sda = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_WIRE_SDA), PinMap_I2C_SDA); 11 | I2C_TypeDef *i2c_scl = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_WIRE_SCL), PinMap_I2C_SCL); 12 | if (i2c_sda == NP) { 13 | Serial.printf("PIN_WIRE_SDA (%d) doesn't match a valid I2C peripheral\n", PIN_WIRE_SDA); 14 | testPassed = false; 15 | } 16 | if (i2c_scl == NP) { 17 | Serial.printf("PIN_WIRE_SCL (%d) doesn't match a valid I2C peripheral\n", PIN_WIRE_SCL); 18 | testPassed = false; 19 | } 20 | if (i2c_sda != i2c_scl) { 21 | Serial.printf("PIN_WIRE_SCL (%d) doesn't match PIN_WIRE_SDA (%d) peripheral\n", PIN_WIRE_SCL, PIN_WIRE_SDA); 22 | testPassed = false; 23 | } 24 | #endif 25 | return testPassed; 26 | } 27 | 28 | #if defined(SERIAL_UART_INSTANCE) 29 | /* 30 | Returns USART_TypeDef corresponding to SERIAL_UART_INSTANCE 31 | */ 32 | USART_TypeDef* getSerialInstance(void) { 33 | #if SERIAL_UART_INSTANCE == 0 || SERIAL_UART_INSTANCE == 101 34 | return LPUART1; 35 | #elif SERIAL_UART_INSTANCE == 1 36 | return USART1; 37 | #elif SERIAL_UART_INSTANCE == 2 38 | return USART2; 39 | #elif SERIAL_UART_INSTANCE == 3 40 | return USART3; 41 | #elif SERIAL_UART_INSTANCE == 4 42 | #if defined(UART4_BASE) 43 | return UART4; 44 | #else 45 | return USART4; 46 | #endif 47 | #elif SERIAL_UART_INSTANCE == 5 48 | #if defined(UART5_BASE) 49 | return UART5; 50 | #else 51 | return USART5; 52 | #endif 53 | #elif SERIAL_UART_INSTANCE == 6 54 | return USART6; 55 | #elif SERIAL_UART_INSTANCE == 7 56 | #if defined(UART7_BASE) 57 | return UART7; 58 | #else 59 | return USART7; 60 | #endif 61 | #elif SERIAL_UART_INSTANCE == 8 62 | #if defined(UART8_BASE) 63 | return UART8; 64 | #else 65 | return USART8; 66 | #endif 67 | #elif SERIAL_UART_INSTANCE == 9 68 | return USART9; 69 | #elif SERIAL_UART_INSTANCE == 10 70 | #if defined(UART10_BASE) 71 | return UART10; 72 | #else 73 | return USART10; 74 | #endif 75 | #else 76 | return NULL; 77 | #endif 78 | } 79 | #endif /* SERIAL_UART_INSTANCE */ 80 | 81 | /* 82 | Checks Serial instances (UART) 83 | Returns true in case of test passed 84 | Returns false in case of test failed 85 | */ 86 | bool checkSerialInstance(void) { 87 | bool testPassed = true; 88 | 89 | #if defined(PIN_SERIAL_RX) && defined(PIN_SERIAL_TX) 90 | USART_TypeDef *uart_rx = (USART_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SERIAL_RX), PinMap_UART_RX); 91 | USART_TypeDef *uart_tx = (USART_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SERIAL_TX), PinMap_UART_TX); 92 | if (uart_rx == NP) { 93 | Serial.printf("PIN_SERIAL_RX (%d) doesn't match a valid UART peripheral\n", PIN_SERIAL_RX); 94 | testPassed = false; 95 | } 96 | if (uart_tx == NP) { 97 | Serial.printf("PIN_SERIAL_TX (%d) doesn't match a valid UART peripheral\n", PIN_SERIAL_TX); 98 | testPassed = false; 99 | } 100 | if (uart_rx != uart_tx) { 101 | Serial.printf("PIN_SERIAL_RX (%d) doesn't match PIN_SERIAL_TX (%d) peripheral\n", PIN_SERIAL_RX, PIN_SERIAL_TX); 102 | testPassed = false; 103 | } 104 | 105 | #if defined(SERIAL_UART_INSTANCE) 106 | USART_TypeDef* usart = getSerialInstance(); 107 | if (usart != uart_tx) { 108 | Serial.printf("SERIAL_UART_INSTANCE (%d) doesn't match PIN_SERIAL_TX (%d) peripheral\n", SERIAL_UART_INSTANCE, PIN_SERIAL_TX); 109 | testPassed = false; 110 | } 111 | #endif 112 | 113 | #endif /* PIN_SERIAL_RX && PIN_SERIAL_TX */ 114 | 115 | return testPassed; 116 | } 117 | 118 | /* 119 | Checks SPI instances 120 | Returns true in case of test passed 121 | Returns false in case of test failed 122 | */ 123 | bool checkSPIInstance(void) { 124 | bool testPassed = true; 125 | 126 | #if defined(PIN_SPI_MOSI) && defined(PIN_SPI_MISO) 127 | SPI_TypeDef *spi_mosi = (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SPI_MOSI), PinMap_SPI_MOSI); 128 | SPI_TypeDef *spi_miso = (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SPI_MISO), PinMap_SPI_MISO); 129 | if (spi_mosi == NP) { 130 | Serial.printf("PIN_SPI_MOSI (%d) doesn't match a valid SPI peripheral\n", PIN_SPI_MOSI); 131 | testPassed = false; 132 | } 133 | if (spi_miso == NP) { 134 | Serial.printf("PIN_SPI_MISO (%d) doesn't match a valid SPI peripheral\n", PIN_SPI_MISO); 135 | testPassed = false; 136 | } 137 | if (spi_mosi != spi_miso) { 138 | Serial.printf("PIN_SPI_MOSI (%d) doesn't match PIN_SPI_MISO (%d) peripheral\n", PIN_SPI_MOSI, PIN_SPI_MISO); 139 | testPassed = false; 140 | } 141 | 142 | #if defined(PIN_SPI_SCK) 143 | SPI_TypeDef *spi_sck = (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(PIN_SPI_SCK), PinMap_SPI_SCLK); 144 | if (spi_sck == NP) { 145 | Serial.printf("PIN_SPI_SCK (%d) doesn't match a valid SPI peripheral\n", PIN_SPI_SCK); 146 | testPassed = false; 147 | } 148 | if (spi_sck != spi_mosi) { 149 | Serial.printf("PIN_SPI_SCK (%d) doesn't match PIN_SPI_MISO (%d) peripheral\n", PIN_SPI_SCK, PIN_SPI_MISO); 150 | testPassed = false; 151 | } 152 | #endif 153 | 154 | #endif /* PIN_SPI_MOSI && PIN_SPI_MISO */ 155 | 156 | #if defined(PIN_SPI_SS) 157 | /* PIN_SPI_SS may be used as software chip select (and not hardware) any pin is valid 158 | thus not possible to check this pin agianst PinMap_SPI_SSEL */ 159 | if (!digitalPinIsValid(PIN_SPI_SS)) { 160 | Serial.printf("PIN_SPI_SS (%d) doesn't match PIN_SPI_MISO (%d) peripheral\n", PIN_SPI_SS, PIN_SPI_MISO); 161 | testPassed = false; 162 | } 163 | #endif 164 | 165 | return testPassed; 166 | } 167 | 168 | /* 169 | Check IP instances (I2C, UART, SPI) 170 | Return true in case of test passed 171 | Return false in case of test failed 172 | */ 173 | bool checkIPInstance(void) { 174 | bool testPassed = true; 175 | 176 | Serial.println("#####"); 177 | Serial.println("Checking IP instances (I2C, UART, SPI)..."); 178 | 179 | if (!checkI2CInstance()) { 180 | testPassed = false; 181 | } 182 | if (!checkSerialInstance()) { 183 | testPassed = false; 184 | } 185 | if (!checkSPIInstance()) { 186 | testPassed = false; 187 | } 188 | Serial.println("End check IP instances (I2C, UART, SPI)"); 189 | return testPassed; 190 | } 191 | -------------------------------------------------------------------------------- /examples/NonReg/CheckVariant/digitalPinsTest.ino: -------------------------------------------------------------------------------- 1 | 2 | #define PNUM(Port, Pin) P ## Port ## Pin 3 | #define PNAME(Port, Pin) P ## Port ## _ ## Pin 4 | #define DECLTESTPNUM(Port, Pin) checkPinNumber(XSTR(PNAME(Port, Pin)), PNAME(Port, Pin), "P"#Port#Pin, PNUM(Port, Pin)) 5 | 6 | /* 7 | Check Pin number 8 | Return true in case of test passed 9 | Return false in case of test failed 10 | */ 11 | bool checkPinNumber(const char* spname, PinName pname, const char* spnum, uint32_t pnum) { 12 | PinName pnamex = digitalPinToPinName(pnum); 13 | if (pnamex != pname) { 14 | Serial.print("Pin number: "); 15 | Serial.printf("%s(%i) indexes PinName:", spnum); 16 | if (pnamex == NC) { 17 | Serial.print("NC"); 18 | } else { 19 | printPinName(pnamex, true, true, false); 20 | } 21 | Serial.print(" --> "); 22 | uint32_t pnumx = pinNametoDigitalPin(pname); 23 | if (pnumx != NUM_DIGITAL_PINS) { 24 | Serial.printf("%s should be %i\n", spnum, pnumx); 25 | } else { 26 | Serial.printf("%s is not in digitalPin[], so %i should not be defined.\n", spname, spnum); 27 | } 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | /* 34 | Check Digital pins 35 | Return true in case of test passed 36 | Return false in case of test failed 37 | */ 38 | bool checkDigitalPins(void) { 39 | bool testPassed = true; 40 | Serial.println("#####"); 41 | Serial.println("Checking digital pins..."); 42 | // Serial.println("\tPin number definition..."); 43 | #ifdef PA0 44 | if (!DECLTESTPNUM(A, 0)) testPassed = false; 45 | #endif 46 | #ifdef PA1 47 | if (!DECLTESTPNUM(A, 1)) testPassed = false; 48 | #endif 49 | #ifdef PA2 50 | if (!DECLTESTPNUM(A, 2)) testPassed = false; 51 | #endif 52 | #ifdef PA3 53 | if (!DECLTESTPNUM(A, 3)) testPassed = false; 54 | #endif 55 | #ifdef PA4 56 | if (!DECLTESTPNUM(A, 4)) testPassed = false; 57 | #endif 58 | #ifdef PA5 59 | if (!DECLTESTPNUM(A, 5)) testPassed = false; 60 | #endif 61 | #ifdef PA6 62 | if (!DECLTESTPNUM(A, 6)) testPassed = false; 63 | #endif 64 | #ifdef PA7 65 | if (!DECLTESTPNUM(A, 7)) testPassed = false; 66 | #endif 67 | #ifdef PA8 68 | if (!DECLTESTPNUM(A, 8)) testPassed = false; 69 | #endif 70 | #ifdef PA9 71 | if (!DECLTESTPNUM(A, 9)) testPassed = false; 72 | #endif 73 | #ifdef PA10 74 | if (!DECLTESTPNUM(A, 10)) testPassed = false; 75 | #endif 76 | #ifdef PA11 77 | if (!DECLTESTPNUM(A, 11)) testPassed = false; 78 | #endif 79 | #ifdef PA12 80 | if (!DECLTESTPNUM(A, 12)) testPassed = false; 81 | #endif 82 | #ifdef PA13 83 | if (!DECLTESTPNUM(A, 13)) testPassed = false; 84 | #endif 85 | #ifdef PA14 86 | if (!DECLTESTPNUM(A, 14)) testPassed = false; 87 | #endif 88 | #ifdef PA15 89 | if (!DECLTESTPNUM(A, 15)) testPassed = false; 90 | #endif 91 | #ifdef PB0 92 | if (!DECLTESTPNUM(B, 0)) testPassed = false; 93 | #endif 94 | #ifdef PB1 95 | if (!DECLTESTPNUM(B, 1)) testPassed = false; 96 | #endif 97 | #ifdef PB2 98 | if (!DECLTESTPNUM(B, 2)) testPassed = false; 99 | #endif 100 | #ifdef PB3 101 | if (!DECLTESTPNUM(B, 3)) testPassed = false; 102 | #endif 103 | #ifdef PB4 104 | if (!DECLTESTPNUM(B, 4)) testPassed = false; 105 | #endif 106 | #ifdef PB5 107 | if (!DECLTESTPNUM(B, 5)) testPassed = false; 108 | #endif 109 | #ifdef PB6 110 | if (!DECLTESTPNUM(B, 6)) testPassed = false; 111 | #endif 112 | #ifdef PB7 113 | if (!DECLTESTPNUM(B, 7)) testPassed = false; 114 | #endif 115 | #ifdef PB8 116 | if (!DECLTESTPNUM(B, 8)) testPassed = false; 117 | #endif 118 | #ifdef PB9 119 | if (!DECLTESTPNUM(B, 9)) testPassed = false; 120 | #endif 121 | #ifdef PB10 122 | if (!DECLTESTPNUM(B, 10)) testPassed = false; 123 | #endif 124 | #ifdef PB11 125 | if (!DECLTESTPNUM(B, 11)) testPassed = false; 126 | #endif 127 | #ifdef PB12 128 | if (!DECLTESTPNUM(B, 12)) testPassed = false; 129 | #endif 130 | #ifdef PB13 131 | if (!DECLTESTPNUM(B, 13)) testPassed = false; 132 | #endif 133 | #ifdef PB14 134 | if (!DECLTESTPNUM(B, 14)) testPassed = false; 135 | #endif 136 | #ifdef PB15 137 | if (!DECLTESTPNUM(B, 15)) testPassed = false; 138 | #endif 139 | #if defined GPIOC_BASE 140 | #ifdef PC0 141 | if (!DECLTESTPNUM(C, 0)) testPassed = false; 142 | #endif 143 | #ifdef PC1 144 | if (!DECLTESTPNUM(C, 1)) testPassed = false; 145 | #endif 146 | #ifdef PC2 147 | if (!DECLTESTPNUM(C, 2)) testPassed = false; 148 | #endif 149 | #ifdef PC3 150 | if (!DECLTESTPNUM(C, 3)) testPassed = false; 151 | #endif 152 | #ifdef PC4 153 | if (!DECLTESTPNUM(C, 4)) testPassed = false; 154 | #endif 155 | #ifdef PC5 156 | if (!DECLTESTPNUM(C, 5)) testPassed = false; 157 | #endif 158 | #ifdef PC6 159 | if (!DECLTESTPNUM(C, 6)) testPassed = false; 160 | #endif 161 | #ifdef PC7 162 | if (!DECLTESTPNUM(C, 7)) testPassed = false; 163 | #endif 164 | #ifdef PC8 165 | if (!DECLTESTPNUM(C, 8)) testPassed = false; 166 | #endif 167 | #ifdef PC9 168 | if (!DECLTESTPNUM(C, 9)) testPassed = false; 169 | #endif 170 | #ifdef PC10 171 | if (!DECLTESTPNUM(C, 10)) testPassed = false; 172 | #endif 173 | #ifdef PC11 174 | if (!DECLTESTPNUM(C, 11)) testPassed = false; 175 | #endif 176 | #ifdef PC12 177 | if (!DECLTESTPNUM(C, 12)) testPassed = false; 178 | #endif 179 | #ifdef PC13 180 | if (!DECLTESTPNUM(C, 13)) testPassed = false; 181 | #endif 182 | #ifdef PC14 183 | if (!DECLTESTPNUM(C, 14)) testPassed = false; 184 | #endif 185 | #ifdef PC15 186 | if (!DECLTESTPNUM(C, 15)) testPassed = false; 187 | #endif 188 | #endif 189 | #if defined GPIOD_BASE 190 | #ifdef PD0 191 | if (!DECLTESTPNUM(D, 0)) testPassed = false; 192 | #endif 193 | #ifdef PD1 194 | if (!DECLTESTPNUM(D, 1)) testPassed = false; 195 | #endif 196 | #ifdef PD2 197 | if (!DECLTESTPNUM(D, 2)) testPassed = false; 198 | #endif 199 | #ifdef PD3 200 | if (!DECLTESTPNUM(D, 3)) testPassed = false; 201 | #endif 202 | #ifdef PD4 203 | if (!DECLTESTPNUM(D, 4)) testPassed = false; 204 | #endif 205 | #ifdef PD5 206 | if (!DECLTESTPNUM(D, 5)) testPassed = false; 207 | #endif 208 | #ifdef PD6 209 | if (!DECLTESTPNUM(D, 6)) testPassed = false; 210 | #endif 211 | #ifdef PD7 212 | if (!DECLTESTPNUM(D, 7)) testPassed = false; 213 | #endif 214 | #ifdef PD8 215 | if (!DECLTESTPNUM(D, 8)) testPassed = false; 216 | #endif 217 | #ifdef PD9 218 | if (!DECLTESTPNUM(D, 9)) testPassed = false; 219 | #endif 220 | #ifdef PD10 221 | if (!DECLTESTPNUM(D, 10)) testPassed = false; 222 | #endif 223 | #ifdef PD11 224 | if (!DECLTESTPNUM(D, 11)) testPassed = false; 225 | #endif 226 | #ifdef PD12 227 | if (!DECLTESTPNUM(D, 12)) testPassed = false; 228 | #endif 229 | #ifdef PD13 230 | if (!DECLTESTPNUM(D, 13)) testPassed = false; 231 | #endif 232 | #ifdef PD14 233 | if (!DECLTESTPNUM(D, 14)) testPassed = false; 234 | #endif 235 | #ifdef PD15 236 | if (!DECLTESTPNUM(D, 15)) testPassed = false; 237 | #endif 238 | #endif 239 | #if defined GPIOE_BASE 240 | #ifdef PE0 241 | if (!DECLTESTPNUM(E, 0)) testPassed = false; 242 | #endif 243 | #ifdef PE1 244 | if (!DECLTESTPNUM(E, 1)) testPassed = false; 245 | #endif 246 | #ifdef PE2 247 | if (!DECLTESTPNUM(E, 2)) testPassed = false; 248 | #endif 249 | #ifdef PE3 250 | if (!DECLTESTPNUM(E, 3)) testPassed = false; 251 | #endif 252 | #ifdef PE4 253 | if (!DECLTESTPNUM(E, 4)) testPassed = false; 254 | #endif 255 | #ifdef PE5 256 | if (!DECLTESTPNUM(E, 5)) testPassed = false; 257 | #endif 258 | #ifdef PE6 259 | if (!DECLTESTPNUM(E, 6)) testPassed = false; 260 | #endif 261 | #ifdef PE7 262 | if (!DECLTESTPNUM(E, 7)) testPassed = false; 263 | #endif 264 | #ifdef PE8 265 | if (!DECLTESTPNUM(E, 8)) testPassed = false; 266 | #endif 267 | #ifdef PE9 268 | if (!DECLTESTPNUM(E, 9)) testPassed = false; 269 | #endif 270 | #ifdef PE10 271 | if (!DECLTESTPNUM(E, 10)) testPassed = false; 272 | #endif 273 | #ifdef PE11 274 | if (!DECLTESTPNUM(E, 11)) testPassed = false; 275 | #endif 276 | #ifdef PE12 277 | if (!DECLTESTPNUM(E, 12)) testPassed = false; 278 | #endif 279 | #ifdef PE13 280 | if (!DECLTESTPNUM(E, 13)) testPassed = false; 281 | #endif 282 | #ifdef PE14 283 | if (!DECLTESTPNUM(E, 14)) testPassed = false; 284 | #endif 285 | #ifdef PE15 286 | if (!DECLTESTPNUM(E, 15)) testPassed = false; 287 | #endif 288 | #endif 289 | #if defined GPIOF_BASE 290 | #ifdef PF0 291 | if (!DECLTESTPNUM(F, 0)) testPassed = false; 292 | #endif 293 | #ifdef PF1 294 | if (!DECLTESTPNUM(F, 1)) testPassed = false; 295 | #endif 296 | #ifdef PF2 297 | if (!DECLTESTPNUM(F, 2)) testPassed = false; 298 | #endif 299 | #ifdef PF3 300 | if (!DECLTESTPNUM(F, 3)) testPassed = false; 301 | #endif 302 | #ifdef PF4 303 | if (!DECLTESTPNUM(F, 4)) testPassed = false; 304 | #endif 305 | #ifdef PF5 306 | if (!DECLTESTPNUM(F, 5)) testPassed = false; 307 | #endif 308 | #ifdef PF6 309 | if (!DECLTESTPNUM(F, 6)) testPassed = false; 310 | #endif 311 | #ifdef PF7 312 | if (!DECLTESTPNUM(F, 7)) testPassed = false; 313 | #endif 314 | #ifdef PF8 315 | if (!DECLTESTPNUM(F, 8)) testPassed = false; 316 | #endif 317 | #ifdef PF9 318 | if (!DECLTESTPNUM(F, 9)) testPassed = false; 319 | #endif 320 | #ifdef PF10 321 | if (!DECLTESTPNUM(F, 10)) testPassed = false; 322 | #endif 323 | #ifdef PF11 324 | if (!DECLTESTPNUM(F, 11)) testPassed = false; 325 | #endif 326 | #ifdef PF12 327 | if (!DECLTESTPNUM(F, 12)) testPassed = false; 328 | #endif 329 | #ifdef PF13 330 | if (!DECLTESTPNUM(F, 13)) testPassed = false; 331 | #endif 332 | #ifdef PF14 333 | if (!DECLTESTPNUM(F, 14)) testPassed = false; 334 | #endif 335 | #ifdef PF15 336 | if (!DECLTESTPNUM(F, 15)) testPassed = false; 337 | #endif 338 | #endif 339 | #if defined GPIOG_BASE 340 | #ifdef PG0 341 | if (!DECLTESTPNUM(G, 0)) testPassed = false; 342 | #endif 343 | #ifdef PG1 344 | if (!DECLTESTPNUM(G, 1)) testPassed = false; 345 | #endif 346 | #ifdef PG2 347 | if (!DECLTESTPNUM(G, 2)) testPassed = false; 348 | #endif 349 | #ifdef PG3 350 | if (!DECLTESTPNUM(G, 3)) testPassed = false; 351 | #endif 352 | #ifdef PG4 353 | if (!DECLTESTPNUM(G, 4)) testPassed = false; 354 | #endif 355 | #ifdef PG5 356 | if (!DECLTESTPNUM(G, 5)) testPassed = false; 357 | #endif 358 | #ifdef PG6 359 | if (!DECLTESTPNUM(G, 6)) testPassed = false; 360 | #endif 361 | #ifdef PG7 362 | if (!DECLTESTPNUM(G, 7)) testPassed = false; 363 | #endif 364 | #ifdef PG8 365 | if (!DECLTESTPNUM(G, 8)) testPassed = false; 366 | #endif 367 | #ifdef PG9 368 | if (!DECLTESTPNUM(G, 9)) testPassed = false; 369 | #endif 370 | #ifdef PG10 371 | if (!DECLTESTPNUM(G, 10)) testPassed = false; 372 | #endif 373 | #ifdef PG11 374 | if (!DECLTESTPNUM(G, 11)) testPassed = false; 375 | #endif 376 | #ifdef PG12 377 | if (!DECLTESTPNUM(G, 12)) testPassed = false; 378 | #endif 379 | #ifdef PG13 380 | if (!DECLTESTPNUM(G, 13)) testPassed = false; 381 | #endif 382 | #ifdef PG14 383 | if (!DECLTESTPNUM(G, 14)) testPassed = false; 384 | #endif 385 | #ifdef PG15 386 | if (!DECLTESTPNUM(G, 15)) testPassed = false; 387 | #endif 388 | #endif 389 | #if defined GPIO_HBASE 390 | #ifdef PH0 391 | if (!DECLTESTPNUM(H, 0)) testPassed = false; 392 | #endif 393 | #ifdef PH1 394 | if (!DECLTESTPNUM(H, 1)) testPassed = false; 395 | #endif 396 | #ifdef PH2 397 | if (!DECLTESTPNUM(H, 2)) testPassed = false; 398 | #endif 399 | #ifdef PH3 400 | if (!DECLTESTPNUM(H, 3)) testPassed = false; 401 | #endif 402 | #ifdef PH4 403 | if (!DECLTESTPNUM(H, 4)) testPassed = false; 404 | #endif 405 | #ifdef PH5 406 | if (!DECLTESTPNUM(H, 5)) testPassed = false; 407 | #endif 408 | #ifdef PH6 409 | if (!DECLTESTPNUM(H, 6)) testPassed = false; 410 | #endif 411 | #ifdef PH7 412 | if (!DECLTESTPNUM(H, 7)) testPassed = false; 413 | #endif 414 | #ifdef PH8 415 | if (!DECLTESTPNUM(H, 8)) testPassed = false; 416 | #endif 417 | #ifdef PH9 418 | if (!DECLTESTPNUM(H, 9)) testPassed = false; 419 | #endif 420 | #ifdef PH10 421 | if (!DECLTESTPNUM(H, 10)) testPassed = false; 422 | #endif 423 | #ifdef PH11 424 | if (!DECLTESTPNUM(H, 11)) testPassed = false; 425 | #endif 426 | #ifdef PH12 427 | if (!DECLTESTPNUM(H, 12)) testPassed = false; 428 | #endif 429 | #ifdef PH13 430 | if (!DECLTESTPNUM(H, 13)) testPassed = false; 431 | #endif 432 | #ifdef PH14 433 | if (!DECLTESTPNUM(H, 14)) testPassed = false; 434 | #endif 435 | #ifdef PH15 436 | if (!DECLTESTPNUM(H, 15)) testPassed = false; 437 | #endif 438 | #endif 439 | #if defined GPIOI_BASE 440 | #ifdef PI0 441 | if (!DECLTESTPNUM(I, 0)) testPassed = false; 442 | #endif 443 | #ifdef PI1 444 | if (!DECLTESTPNUM(I, 1)) testPassed = false; 445 | #endif 446 | #ifdef PI2 447 | if (!DECLTESTPNUM(I, 2)) testPassed = false; 448 | #endif 449 | #ifdef PI3 450 | if (!DECLTESTPNUM(I, 3)) testPassed = false; 451 | #endif 452 | #ifdef PI4 453 | if (!DECLTESTPNUM(I, 4)) testPassed = false; 454 | #endif 455 | #ifdef PI5 456 | if (!DECLTESTPNUM(I, 5)) testPassed = false; 457 | #endif 458 | #ifdef PI6 459 | if (!DECLTESTPNUM(I, 6)) testPassed = false; 460 | #endif 461 | #ifdef PI7 462 | if (!DECLTESTPNUM(I, 7)) testPassed = false; 463 | #endif 464 | #ifdef PI8 465 | if (!DECLTESTPNUM(I, 8)) testPassed = false; 466 | #endif 467 | #ifdef PI9 468 | if (!DECLTESTPNUM(I, 9)) testPassed = false; 469 | #endif 470 | #ifdef PI10 471 | if (!DECLTESTPNUM(I, 10)) testPassed = false; 472 | #endif 473 | #ifdef PI11 474 | if (!DECLTESTPNUM(I, 11)) testPassed = false; 475 | #endif 476 | #ifdef PI12 477 | if (!DECLTESTPNUM(I, 12)) testPassed = false; 478 | #endif 479 | #ifdef PI13 480 | if (!DECLTESTPNUM(I, 13)) testPassed = false; 481 | #endif 482 | #ifdef PI14 483 | if (!DECLTESTPNUM(I, 14)) testPassed = false; 484 | #endif 485 | #ifdef PI15 486 | if (!DECLTESTPNUM(I, 15)) testPassed = false; 487 | #endif 488 | #endif 489 | #if defined GPIOJ_BASE 490 | #ifdef PJ0 491 | if (!DECLTESTPNUM(J, 0)) testPassed = false; 492 | #endif 493 | #ifdef PJ1 494 | if (!DECLTESTPNUM(J, 1)) testPassed = false; 495 | #endif 496 | #ifdef PJ2 497 | if (!DECLTESTPNUM(J, 2)) testPassed = false; 498 | #endif 499 | #ifdef PJ3 500 | if (!DECLTESTPNUM(J, 3)) testPassed = false; 501 | #endif 502 | #ifdef PJ4 503 | if (!DECLTESTPNUM(J, 4)) testPassed = false; 504 | #endif 505 | #ifdef PJ5 506 | if (!DECLTESTPNUM(J, 5)) testPassed = false; 507 | #endif 508 | #ifdef PJ6 509 | if (!DECLTESTPNUM(J, 6)) testPassed = false; 510 | #endif 511 | #ifdef PJ7 512 | if (!DECLTESTPNUM(J, 7)) testPassed = false; 513 | #endif 514 | #ifdef PJ8 515 | if (!DECLTESTPNUM(J, 8)) testPassed = false; 516 | #endif 517 | #ifdef PJ9 518 | if (!DECLTESTPNUM(J, 9)) testPassed = false; 519 | #endif 520 | #ifdef PJ10 521 | if (!DECLTESTPNUM(J, 10)) testPassed = false; 522 | #endif 523 | #ifdef PJ11 524 | if (!DECLTESTPNUM(J, 11)) testPassed = false; 525 | #endif 526 | #ifdef PJ12 527 | if (!DECLTESTPNUM(J, 12)) testPassed = false; 528 | #endif 529 | #ifdef PJ13 530 | if (!DECLTESTPNUM(J, 13)) testPassed = false; 531 | #endif 532 | #ifdef PJ14 533 | if (!DECLTESTPNUM(J, 14)) testPassed = false; 534 | #endif 535 | #ifdef PJ15 536 | if (!DECLTESTPNUM(J, 15)) testPassed = false; 537 | #endif 538 | #endif 539 | #if defined GPIOK_BASE 540 | #ifdef PK0 541 | if (!DECLTESTPNUM(K, 0)) testPassed = false; 542 | #endif 543 | #ifdef PK1 544 | if (!DECLTESTPNUM(K, 1)) testPassed = false; 545 | #endif 546 | #ifdef PK2 547 | if (!DECLTESTPNUM(K, 2)) testPassed = false; 548 | #endif 549 | #ifdef PK3 550 | if (!DECLTESTPNUM(K, 3)) testPassed = false; 551 | #endif 552 | #ifdef PK4 553 | if (!DECLTESTPNUM(K, 4)) testPassed = false; 554 | #endif 555 | #ifdef PK5 556 | if (!DECLTESTPNUM(K, 5)) testPassed = false; 557 | #endif 558 | #ifdef PK6 559 | if (!DECLTESTPNUM(K, 6)) testPassed = false; 560 | #endif 561 | #ifdef PK7 562 | if (!DECLTESTPNUM(K, 7)) testPassed = false; 563 | #endif 564 | #ifdef PK8 565 | if (!DECLTESTPNUM(K, 8)) testPassed = false; 566 | #endif 567 | #ifdef PK9 568 | if (!DECLTESTPNUM(K, 9)) testPassed = false; 569 | #endif 570 | #ifdef PK10 571 | if (!DECLTESTPNUM(K, 10)) testPassed = false; 572 | #endif 573 | #ifdef PK11 574 | if (!DECLTESTPNUM(K, 11)) testPassed = false; 575 | #endif 576 | #ifdef PK12 577 | if (!DECLTESTPNUM(K, 12)) testPassed = false; 578 | #endif 579 | #ifdef PK13 580 | if (!DECLTESTPNUM(K, 13)) testPassed = false; 581 | #endif 582 | #ifdef PK14 583 | if (!DECLTESTPNUM(K, 14)) testPassed = false; 584 | #endif 585 | #ifdef PK15 586 | if (!DECLTESTPNUM(K, 15)) testPassed = false; 587 | #endif 588 | #endif 589 | 590 | Serial.println("End check digital pins"); 591 | return testPassed; 592 | } 593 | -------------------------------------------------------------------------------- /examples/NonReg/HardwareTimer/HardwareTimer_OutputInput_test/HardwareTimer_OutputInput_test.ino: -------------------------------------------------------------------------------- 1 | /*************************************** 2 | ** Brief 3 | ***************************************/ 4 | /* 5 | HardwareTimer Non Regression test 6 | This example is used to verify whether major HardwareTimer usecase are working. 7 | 8 | Designed to work on Nucleo_L476RG 9 | TIM1 ch1N and ch2 are used for output generation (TIM1_CH1N_PIN, and TIM1_CH2_PIN). 10 | It is important that both channel are on the same timer, in order to check influence on channel dependant API. 11 | Management of interruption is done with variable increment. 12 | TIM8 ch1/ch2 are used to measure frequency and duty cycle of TIM1_CH1N output generated signal 13 | TIM8 ch3/ch4 are used to measure frequency and duty cycle of TIM1_CH2 output generated signal 14 | 15 | Regular channel and complementary channel (TIM1_CH1N) are tested. 16 | 17 | Please wire : 18 | TIM1_CH1N_PIN to TIM8_CH1_PIN 19 | TIM1_CH2_PIN to TIM8_CH3_PIN 20 | 21 | */ 22 | 23 | /*************************************** 24 | ** Prerequisite 25 | ***************************************/ 26 | /* 27 | Please wire : 28 | TIM1_CH1N_PIN to TIM8_CH1_PIN 29 | TIM1_CH2_PIN to TIM8_CH3_PIN 30 | */ 31 | 32 | /*************************************** 33 | ** Defines 34 | ***************************************/ 35 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 36 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 37 | #endif 38 | 39 | 40 | #if !defined(ARDUINO_NUCLEO_L476RG) 41 | #error "Sketch is applicable to NUCLEO_L476RG" 42 | #endif 43 | // For L476 only 44 | // TIM ouput 45 | #define TIM1_CH1N_PIN PB13 // PB_13 CN_10 pin 30 46 | #define TIM1_CH2_PIN PA9 // PA_9 D8 47 | 48 | #define Output1_channel 1 49 | #define Output2_channel 2 50 | 51 | // TIM input 52 | #define TIM8_CH1_PIN PC_6_ALT1 // CN10 pin 4 Use also channel2 for freq/duty measurement 53 | #define Freq1_channelRising 1 54 | #define Freq1_channelFalling 2 55 | 56 | #define TIM8_CH3_PIN PC_8_ALT1 // CN10 pin 2 Use also channel4 for freq/duty measurement 57 | #define Freq2_channelRising 3 58 | #define Freq2_channelFalling 4 59 | 60 | #define OUTPUT_FREQUENCY 10000 // Hz 61 | #define OUTPUT_DUTY1 20 // percentage 62 | #define OUTPUT_DUTY2 30 // percentage 63 | 64 | #define TEMPO_BEFORE_MEASUREMENT 500 // millisecondes 65 | #define TOLERANCE 10 // Percentage 66 | #define EXPECTED_INTERRUPT_COUNT ((TEMPO_BEFORE_MEASUREMENT * OUTPUT_FREQUENCY) / 1000) 67 | 68 | enum Status 69 | { 70 | PASSED = 0, 71 | FAILED = 1 72 | }; 73 | 74 | /*************************************** 75 | ** Global variables 76 | ***************************************/ 77 | 78 | uint32_t channel1; 79 | uint32_t channel2; 80 | 81 | HardwareTimer *MyTim_output; 82 | HardwareTimer *MyTim_input; 83 | 84 | uint32_t Output_Update = 0; 85 | uint32_t Output_Compare1 = 0; 86 | uint32_t Output_Compare2 = 0; 87 | 88 | volatile uint32_t Frequency1_Measured; 89 | volatile uint32_t Dutycycle1_Measured; 90 | volatile uint32_t LastPeriod1_Capture = 0; 91 | volatile uint32_t Current1_Capture; 92 | volatile uint32_t HighState1_Measured; 93 | volatile uint32_t Frequency2_Measured; 94 | volatile uint32_t Dutycycle2_Measured; 95 | volatile uint32_t LastPeriod2_Capture = 0; 96 | volatile uint32_t Current2_Capture; 97 | volatile uint32_t HighState2_Measured; 98 | uint32_t input_freq = 0; 99 | 100 | volatile uint32_t rolloverCompare1Count = 0; 101 | volatile uint32_t rolloverCompare2Count = 0; 102 | 103 | uint32_t test_step = 0; 104 | uint32_t test_Status = PASSED; 105 | 106 | /*************************************** 107 | ** Interrupt callback 108 | ***************************************/ 109 | /******** Output *****/ 110 | void output_Update_IT_callback(void) 111 | { 112 | Output_Update++; 113 | } 114 | 115 | void Output_Compare1_IT_callback(void) 116 | { 117 | Output_Compare1++; 118 | } 119 | 120 | void Output_Compare2_IT_callback(void) 121 | { 122 | Output_Compare2++; 123 | } 124 | 125 | /******** Input 1 *****/ 126 | void Input_Capture1_Rising_IT_callback(void) 127 | { 128 | Current1_Capture = MyTim_input->getCaptureCompare(Freq1_channelRising); 129 | /* frequency computation */ 130 | if (Current1_Capture > LastPeriod1_Capture) 131 | { 132 | Frequency1_Measured = input_freq / (Current1_Capture - LastPeriod1_Capture); 133 | Dutycycle1_Measured = (HighState1_Measured * 100) / (Current1_Capture - LastPeriod1_Capture); 134 | } 135 | else if (Current1_Capture <= LastPeriod1_Capture) 136 | { 137 | /* 0x1000 is max overflow value */ 138 | Frequency1_Measured = input_freq / (0x10000 + Current1_Capture - LastPeriod1_Capture); 139 | Dutycycle1_Measured = (HighState1_Measured * 100) / (0x10000 + Current1_Capture - LastPeriod1_Capture); 140 | } 141 | 142 | LastPeriod1_Capture = Current1_Capture; 143 | rolloverCompare1Count = 0; 144 | } 145 | 146 | void Input_Capture1_Falling_IT_callback(void) 147 | { 148 | /* prepare DutyCycle computation */ 149 | Current1_Capture = MyTim_input->getCaptureCompare(Freq1_channelFalling); 150 | 151 | if (Current1_Capture > LastPeriod1_Capture) 152 | { 153 | HighState1_Measured = Current1_Capture - LastPeriod1_Capture; 154 | } 155 | else if (Current1_Capture <= LastPeriod1_Capture) 156 | { 157 | /* 0x1000 is max overflow value */ 158 | HighState1_Measured = 0x10000 + Current1_Capture - LastPeriod1_Capture; 159 | } 160 | } 161 | 162 | /******** Input 2 *****/ 163 | void Input_Capture2_Rising_IT_callback(void) 164 | { 165 | Current2_Capture = MyTim_input->getCaptureCompare(Freq2_channelRising); 166 | /* frequency computation */ 167 | if (Current2_Capture > LastPeriod2_Capture) 168 | { 169 | Frequency2_Measured = input_freq / (Current2_Capture - LastPeriod2_Capture); 170 | Dutycycle2_Measured = (HighState2_Measured * 100) / (Current2_Capture - LastPeriod2_Capture); 171 | } 172 | else if (Current2_Capture <= LastPeriod2_Capture) 173 | { 174 | /* 0x1000 is max overflow value */ 175 | Frequency2_Measured = input_freq / (0x10000 + Current2_Capture - LastPeriod2_Capture); 176 | Dutycycle2_Measured = (HighState2_Measured * 100) / (0x10000 + Current2_Capture - LastPeriod2_Capture); 177 | } 178 | 179 | LastPeriod2_Capture = Current2_Capture; 180 | rolloverCompare2Count = 0; 181 | } 182 | 183 | void Input_Capture2_Falling_IT_callback(void) 184 | { 185 | /* prepare DutyCycle computation */ 186 | Current2_Capture = MyTim_input->getCaptureCompare(Freq2_channelFalling); 187 | 188 | if (Current2_Capture > LastPeriod2_Capture) 189 | { 190 | HighState2_Measured = Current2_Capture - LastPeriod2_Capture; 191 | } 192 | else if (Current2_Capture <= LastPeriod2_Capture) 193 | { 194 | /* 0x1000 is max overflow value */ 195 | HighState2_Measured = 0x10000 + Current2_Capture - LastPeriod2_Capture; 196 | } 197 | } 198 | 199 | /******** Input rollover *****/ 200 | /* In case of timer rollover, frequency is to low to be measured set values to 0 201 | To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. */ 202 | void Rollover_IT_callback(void) 203 | { 204 | rolloverCompare1Count++; 205 | rolloverCompare2Count++; 206 | if (rolloverCompare1Count > 1) 207 | { 208 | Frequency1_Measured = 0; 209 | Dutycycle1_Measured = 0; 210 | } 211 | 212 | if (rolloverCompare2Count > 1) 213 | { 214 | Frequency2_Measured = 0; 215 | Dutycycle2_Measured = 0; 216 | } 217 | } 218 | 219 | /*************************************** 220 | ** Verify_output 221 | ***************************************/ 222 | void Verify_output(uint32_t index, uint32_t expected_freq, uint32_t expected_duty) 223 | { 224 | int32_t delta_freq; 225 | int32_t delta_duty; 226 | volatile uint32_t Frequency_Measured, Dutycycle_Measured; 227 | 228 | if (index == 1) 229 | { 230 | // Wait before 1st measurement only 231 | delay(TEMPO_BEFORE_MEASUREMENT); 232 | 233 | Frequency_Measured = Frequency1_Measured; 234 | Dutycycle_Measured = Dutycycle1_Measured; 235 | Serial.print(""); 236 | Serial.print("Step "); 237 | Serial.println(test_step); 238 | } 239 | else 240 | { 241 | Frequency_Measured = Frequency2_Measured; 242 | Dutycycle_Measured = Dutycycle2_Measured; 243 | } 244 | 245 | delta_freq = expected_freq - Frequency_Measured; 246 | delta_duty = expected_duty - Dutycycle_Measured; 247 | 248 | Serial.print((String) " Freq " + index); 249 | 250 | if ((uint32_t)abs(delta_freq) <= ((expected_freq * TOLERANCE) / 100)) 251 | { 252 | Serial.println((String) " PASSED : Freq = " + Frequency_Measured); 253 | } 254 | else 255 | { 256 | Serial.print((String) " FAILED : "); 257 | Serial.print((String) " expected Freq = " + expected_freq); 258 | Serial.println((String) " Measured Freq = " + Frequency_Measured); 259 | test_Status = FAILED; 260 | } 261 | 262 | Serial.print((String) " Duty " + index); 263 | if ((uint32_t)abs(delta_duty) <= ((expected_duty * TOLERANCE) / 100)) 264 | { 265 | Serial.println((String) " PASSED"); 266 | } 267 | else 268 | { 269 | Serial.print((String) " FAILED : "); 270 | Serial.print((String) " expected Duty = " + expected_duty); 271 | Serial.println((String) " Measured Duty = " + Dutycycle_Measured); 272 | test_Status = FAILED; 273 | } 274 | } 275 | 276 | /*************************************** 277 | ** Verify_output_interrupts 278 | ***************************************/ 279 | void Verify_output_interrupts(uint32_t expected_update, uint32_t expected_compare1, uint32_t expected_compare2) 280 | { 281 | int32_t delta_Output_Update = expected_update - Output_Update; 282 | int32_t delta_Output_Compare1 = expected_compare1 - Output_Compare1; 283 | int32_t delta_Output_Compare2 = expected_compare2 - Output_Compare2; 284 | 285 | if ((uint32_t)abs(delta_Output_Compare1) > ((expected_compare1 * TOLERANCE) / 100)) 286 | { 287 | Serial.println((String) " Interrupt FAILED: CC1 expected " + expected_compare1 + " get " + Output_Compare1 + "delta_Output_Compare1" + delta_Output_Compare1); 288 | test_Status = FAILED; 289 | } 290 | else if ((uint32_t)abs(delta_Output_Compare2) > ((expected_compare2 * TOLERANCE) / 100)) 291 | { 292 | Serial.println((String) " Interrupt FAILED: CC2 expected " + expected_compare1 + " get " + Output_Compare2); 293 | test_Status = FAILED; 294 | } 295 | else 296 | 297 | if ((uint32_t)abs(delta_Output_Update) > ((expected_update * TOLERANCE) / 100)) 298 | { 299 | Serial.println((String) " Interrupt FAILED: UPDATE expected" + expected_update + " get " + Output_Update); 300 | test_Status = FAILED; 301 | } 302 | else 303 | { 304 | Serial.println(" Interrupt PASSED:"); 305 | } 306 | } 307 | 308 | void reset_interrupt_count() 309 | { 310 | Output_Update = 0; 311 | Output_Compare1 = 0; 312 | Output_Compare2 = 0; 313 | } 314 | 315 | /*************************************** 316 | ** Setup 317 | ***************************************/ 318 | 319 | void setup() 320 | { 321 | // Serial monitor 322 | Serial.begin(115200); 323 | 324 | // No need to configure timer ouput/input pins, it will be done by HardwareTimer configuration 325 | 326 | /***** Output *****/ 327 | TIM_TypeDef *Instance_output = TIM1; 328 | 329 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup function is finished. 330 | MyTim_output = new HardwareTimer(Instance_output); 331 | 332 | /***** Input *****/ 333 | TIM_TypeDef *Instance_input = TIM8; 334 | 335 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup function is finished. 336 | MyTim_input = new HardwareTimer(Instance_input); 337 | 338 | // Compute this input scale factor only once 339 | input_freq = MyTim_input->getTimerClkFreq() / MyTim_input->getPrescaleFactor(); 340 | 341 | Serial.println("--- Start HardwareTimer test ---"); 342 | Serial.println("Did you wire:"); 343 | Serial.println("* PB13 to PC6 ?"); 344 | Serial.println("* PA9 to PC8 ?"); 345 | Serial.println(""); 346 | } 347 | 348 | /*************************************** 349 | ** loop 350 | ***************************************/ 351 | 352 | void loop() 353 | { 354 | 355 | /********* Configure input measurement for output test ***/ 356 | // Configure Input measurement 357 | MyTim_input->setMode(Freq1_channelRising, TIMER_INPUT_FREQ_DUTY_MEASUREMENT, TIM8_CH1_PIN); 358 | 359 | // With a PrescalerFactor = 1, the minimum frequency value to measure is : TIM counter clock / CCR MAX 360 | // = (SystemCoreClock) / 65535 361 | // Example on Nucleo_L476RG with systemClock at 80MHz, the minimum frequency is around 1,2 khz 362 | // To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. 363 | // The maximum frequency depends on processing of both interruptions and thus depend on board used 364 | // Example on Nucleo_L476RG with systemClock at 80MHz the interruptions processing is around 10 microseconds and thus Max frequency is around 100kHz 365 | uint32_t PrescalerFactor = 1; 366 | MyTim_input->setPrescaleFactor(PrescalerFactor); 367 | MyTim_input->setOverflow(0x10000); // Max Period value to have the largest possible time to detect rising edge and avoid timer rollover 368 | MyTim_input->attachInterrupt(Freq1_channelRising, Input_Capture1_Rising_IT_callback); 369 | MyTim_input->attachInterrupt(Freq1_channelFalling, Input_Capture1_Falling_IT_callback); 370 | MyTim_input->attachInterrupt(Rollover_IT_callback); 371 | 372 | MyTim_input->setMode(Freq2_channelRising, TIMER_INPUT_FREQ_DUTY_MEASUREMENT, TIM8_CH3_PIN); 373 | MyTim_input->attachInterrupt(Freq2_channelRising, Input_Capture2_Rising_IT_callback); 374 | MyTim_input->attachInterrupt(Freq2_channelFalling, Input_Capture2_Falling_IT_callback); 375 | 376 | MyTim_input->resume(); 377 | 378 | delay(1000); 379 | 380 | /********* Output test ***/ 381 | test_step++; 382 | 383 | MyTim_output->setOverflow((1000000 / OUTPUT_FREQUENCY), MICROSEC_FORMAT); 384 | MyTim_output->attachInterrupt(output_Update_IT_callback); 385 | MyTim_output->resume(); 386 | reset_interrupt_count(); 387 | Verify_output(1, 0, 0); 388 | Verify_output(2, 0, 0); 389 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, 0); 390 | test_step++; 391 | 392 | MyTim_output->detachInterrupt(); 393 | reset_interrupt_count(); 394 | Verify_output(1, 0, 0); 395 | Verify_output(2, 0, 0); 396 | Verify_output_interrupts(0, 0, 0); 397 | test_step++; 398 | 399 | MyTim_output->pause(); 400 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_COMPARE_PWM1, TIM1_CH1N_PIN); 401 | MyTim_output->setOverflow((1000000 / OUTPUT_FREQUENCY), MICROSEC_FORMAT); 402 | MyTim_output->setCaptureCompare(Output1_channel, OUTPUT_DUTY1, PERCENT_COMPARE_FORMAT); 403 | MyTim_output->resume(); 404 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 405 | Verify_output(2, 0, 0); 406 | test_step++; 407 | 408 | MyTim_output->pause(); 409 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_COMPARE_TOGGLE, TIM1_CH1N_PIN); 410 | MyTim_output->resume(); 411 | Verify_output(1, OUTPUT_FREQUENCY / 2, 50); // in PWM2, output is the complementary of PW1 412 | Verify_output(2, 0, 0); 413 | test_step++; 414 | 415 | MyTim_output->pause(); 416 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_COMPARE_PWM2, TIM1_CH1N_PIN); 417 | MyTim_output->resume(); 418 | Verify_output(1, OUTPUT_FREQUENCY, 100 - OUTPUT_DUTY1); // in PWM2, output is the complementary of PW1 419 | Verify_output(2, 0, 0); 420 | test_step++; 421 | 422 | MyTim_output->pause(); 423 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_COMPARE_PWM1, TIM1_CH1N_PIN); 424 | MyTim_output->resume(); 425 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 426 | Verify_output(2, 0, 0); 427 | test_step++; 428 | 429 | MyTim_output->pause(); 430 | MyTim_output->setMode(Output2_channel, TIMER_OUTPUT_COMPARE_PWM1, TIM1_CH2_PIN); 431 | MyTim_output->setCaptureCompare(Output2_channel, OUTPUT_DUTY2, PERCENT_COMPARE_FORMAT); 432 | MyTim_output->resumeChannel(Output2_channel); 433 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 434 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 435 | test_step++; 436 | 437 | MyTim_output->pauseChannel(Output1_channel); 438 | Verify_output(1, 0, 0); 439 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 440 | test_step++; 441 | 442 | MyTim_output->resumeChannel(Output1_channel); 443 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 444 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 445 | Verify_output_interrupts(0, 0, 0); // interrupt not yet activated 446 | test_step++; 447 | 448 | MyTim_output->attachInterrupt(output_Update_IT_callback); 449 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 450 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 451 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, 0); // interrupt activated for update only 452 | reset_interrupt_count(); 453 | test_step++; 454 | 455 | MyTim_output->pauseChannel(Output1_channel); 456 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_DISABLED); 457 | MyTim_output->resumeChannel(Output1_channel); 458 | Verify_output(1, 0, 0); // in PWM2, output is the complementary of PW1 459 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 460 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, 0); // interrupt activated for update only 461 | test_step++; 462 | 463 | MyTim_output->pauseChannel(Output1_channel); 464 | MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_COMPARE_PWM1, TIM1_CH1N_PIN); 465 | MyTim_output->resumeChannel(Output1_channel); 466 | MyTim_output->attachInterrupt(Output1_channel, Output_Compare1_IT_callback); 467 | reset_interrupt_count(); 468 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 469 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 470 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT, 0); 471 | 472 | test_step++; 473 | 474 | MyTim_output->attachInterrupt(Output2_channel, Output_Compare2_IT_callback); 475 | reset_interrupt_count(); 476 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 477 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 478 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT); 479 | 480 | test_step++; 481 | 482 | MyTim_output->pause(); 483 | reset_interrupt_count(); 484 | Verify_output(1, 0, 0); 485 | Verify_output(2, 0, 0); 486 | Verify_output_interrupts(0, 0, 0); 487 | 488 | test_step++; 489 | 490 | MyTim_output->resumeChannel(Output1_channel); 491 | MyTim_output->resumeChannel(Output2_channel); 492 | reset_interrupt_count(); 493 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 494 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 495 | Verify_output_interrupts(0, EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT); 496 | test_step++; 497 | 498 | MyTim_output->resume(); 499 | reset_interrupt_count(); 500 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 501 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 502 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT); 503 | test_step++; 504 | 505 | MyTim_output->pauseChannel(Output1_channel); 506 | MyTim_output->pauseChannel(Output2_channel); 507 | reset_interrupt_count(); 508 | Verify_output(1, 0, 0); 509 | Verify_output(2, 0, 0); 510 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, 0); 511 | test_step++; 512 | 513 | MyTim_output->resume(); 514 | reset_interrupt_count(); 515 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 516 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 517 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT); 518 | test_step++; 519 | 520 | PrescalerFactor = MyTim_output->getPrescaleFactor(); 521 | MyTim_output->setPrescaleFactor(PrescalerFactor + 1); 522 | reset_interrupt_count(); 523 | Verify_output(1, OUTPUT_FREQUENCY / 2, OUTPUT_DUTY1); 524 | Verify_output(2, OUTPUT_FREQUENCY / 2, OUTPUT_DUTY2); 525 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT / 2, EXPECTED_INTERRUPT_COUNT / 2, EXPECTED_INTERRUPT_COUNT / 2); 526 | test_step++; 527 | 528 | PrescalerFactor = MyTim_output->getPrescaleFactor(); 529 | MyTim_output->setPrescaleFactor(PrescalerFactor - 1); 530 | reset_interrupt_count(); 531 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); // suppose initial prescaler = 1 532 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 533 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT, EXPECTED_INTERRUPT_COUNT); 534 | test_step++; 535 | 536 | if (!MyTim_output->hasInterrupt() || !MyTim_output->hasInterrupt(Output1_channel) || !MyTim_output->hasInterrupt(Output2_channel)) 537 | { 538 | Serial.println((String) " hasInterrupt() FAILED" + MyTim_output->hasInterrupt() + " " + MyTim_output->hasInterrupt(Output1_channel) + " " + MyTim_output->hasInterrupt(Output1_channel)); 539 | test_Status = FAILED; 540 | } 541 | 542 | MyTim_output->detachInterrupt(Output1_channel); 543 | reset_interrupt_count(); 544 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); // suppose initial prescaler = 1 545 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 546 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, EXPECTED_INTERRUPT_COUNT); 547 | if (!MyTim_output->hasInterrupt() || MyTim_output->hasInterrupt(Output1_channel) || !MyTim_output->hasInterrupt(Output2_channel)) 548 | { 549 | Serial.println(" hasInterrupt() FAILED"); 550 | test_Status = FAILED; 551 | } 552 | test_step++; 553 | 554 | MyTim_output->detachInterrupt(Output2_channel); 555 | reset_interrupt_count(); 556 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); // suppose initial prescaler = 1 557 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 558 | Verify_output_interrupts(EXPECTED_INTERRUPT_COUNT, 0, 0); 559 | if (!MyTim_output->hasInterrupt() || MyTim_output->hasInterrupt(Output1_channel) || MyTim_output->hasInterrupt(Output2_channel)) 560 | { 561 | Serial.println(" hasInterrupt() FAILED"); 562 | test_Status = FAILED; 563 | } 564 | test_step++; 565 | 566 | MyTim_output->detachInterrupt(); 567 | reset_interrupt_count(); 568 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); // suppose initial prescaler = 1 569 | Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); 570 | Verify_output_interrupts(0, 0, 0); 571 | reset_interrupt_count(); 572 | if (MyTim_output->hasInterrupt() || MyTim_output->hasInterrupt(Output1_channel) || MyTim_output->hasInterrupt(Output1_channel)) 573 | { 574 | Serial.println(" hasInterrupt() FAILED"); 575 | test_Status = FAILED; 576 | } 577 | test_step++; 578 | 579 | MyTim_output->pause(); 580 | MyTim_output->setPWM(Output1_channel, TIM1_CH1N_PIN, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 581 | Verify_output(1, OUTPUT_FREQUENCY, OUTPUT_DUTY1); 582 | test_step++; 583 | 584 | Serial.print((String) "************* Status:"); 585 | if (test_Status == PASSED) 586 | { 587 | Serial.println(" PASSED **********"); 588 | } 589 | else 590 | { 591 | Serial.println(" FAILED **********"); 592 | } 593 | 594 | while (1) 595 | { 596 | }; 597 | } 598 | -------------------------------------------------------------------------------- /examples/NonReg/PulseIn/PulseIn.ino: -------------------------------------------------------------------------------- 1 | /* 2 | pulseIn 3 | 4 | This sketch allows to test pulseIn() and pulseInLong() functions. 5 | 6 | A PWM signal is generated on 'pwm' pin and then measures are performed on 7 | 'in' pin for the HIGH and LOW state. 8 | The min and max value for both are displayed on the Serial console. 9 | 10 | Creation 15 Sep 2017 11 | by Frederic Pillon 12 | 13 | This example code is in the public domain. 14 | 15 | https://www.arduino.cc/en/Reference/PulseIn 16 | */ 17 | 18 | 19 | // Use pulseInLong()? 20 | #define USE_PULSEINLONG 1 21 | 22 | static uint32_t pwm = 9; 23 | static uint32_t in = 4; 24 | static uint32_t state = HIGH; 25 | 26 | void setup() { 27 | pinMode(in, INPUT); 28 | Serial.begin(115200); 29 | analogWrite(pwm, 127); 30 | } 31 | static uint32_t min_duration_low = (uint32_t)(-1); 32 | static uint32_t max_duration_low = 0; 33 | static uint32_t min_duration_high = (uint32_t)(-1); 34 | static uint32_t max_duration_high = 0; 35 | #if USE_PULSEINLONG 36 | static uint32_t min_durationLong_low = (uint32_t)(-1); 37 | static uint32_t max_durationLong_low = 0; 38 | static uint32_t min_durationLong_high = (uint32_t)(-1); 39 | static uint32_t max_durationLong_high = 0; 40 | #endif 41 | 42 | void loop() { 43 | uint32_t duration = 0; 44 | duration = pulseIn(in, state); 45 | #if USE_PULSEINLONG 46 | uint32_t durationLong = 0; 47 | durationLong = pulseInLong(in, state); 48 | #endif 49 | if (state == HIGH) { 50 | Serial.print("PulseIn HIGH state duration:"); 51 | min_duration_high=min(min_duration_high,duration); 52 | max_duration_high=max(max_duration_high,duration); 53 | Serial.print(" min= "); 54 | Serial.print(min_duration_high); 55 | Serial.print(" max= "); 56 | Serial.print(max_duration_high); 57 | #if USE_PULSEINLONG 58 | min_durationLong_high=min(min_durationLong_high,durationLong); 59 | max_durationLong_high=max(max_durationLong_high,durationLong); 60 | Serial.print(" min (long)= "); 61 | Serial.print(min_durationLong_high); 62 | Serial.print(" max (long)= "); 63 | Serial.print(max_durationLong_high); 64 | #endif 65 | state = LOW; 66 | } 67 | else { 68 | Serial.print("PulseIn LOW state duration:"); 69 | min_duration_low=min(min_duration_low,duration); 70 | max_duration_low=max(max_duration_low,duration); 71 | Serial.print(" min= "); 72 | Serial.print(min_duration_low); 73 | Serial.print(" max= "); 74 | Serial.print(max_duration_low); 75 | #if USE_PULSEINLONG 76 | min_durationLong_low=min(min_durationLong_low,durationLong); 77 | max_durationLong_low=max(max_durationLong_low,durationLong); 78 | Serial.print(" min (long)= "); 79 | Serial.print(min_durationLong_low); 80 | Serial.print(" max (long)= "); 81 | Serial.print(max_durationLong_low); 82 | #endif 83 | state = HIGH; 84 | } 85 | Serial.println(); 86 | delay(1000); 87 | } 88 | -------------------------------------------------------------------------------- /examples/NonReg/RTC/RTC_Tests/RTC_Config.ino: -------------------------------------------------------------------------------- 1 | 2 | void rtc_config(STM32RTC::Source_Clock source, STM32RTC::Hour_Format format, const char* date, const char* time) { 3 | if (!IS_CLOCK_SOURCE(source)) { 4 | Serial.println("Wrong clock source"); 5 | return; 6 | } 7 | if (!IS_HOUR_FORMAT(format)) { 8 | Serial.println("Wrong hour format"); 9 | return; 10 | } 11 | if (rtc.isConfigured()) 12 | rtc.end(); 13 | 14 | rtc.setClockSource(source); 15 | hourFormat = format; 16 | rtc_setTime(date, time); 17 | } 18 | 19 | void rtc_setTime(const char* date, const char* time) { 20 | initDateTime(date, time); 21 | rtc.begin(hourFormat); 22 | 23 | // Set the time 24 | rtc.setHours(hours, period); 25 | rtc.setMinutes(minutes); 26 | rtc.setSeconds(seconds); 27 | 28 | // Set the date 29 | rtc.setWeekDay(weekDay); 30 | rtc.setDay(day); 31 | rtc.setMonth(month); 32 | rtc.setYear(year); 33 | 34 | // you can use also 35 | //rtc.setTime(hours, minutes, seconds); 36 | //rtc.setDate(weekDay, day, month, year); 37 | delay(100); 38 | } -------------------------------------------------------------------------------- /examples/NonReg/RTC/RTC_Tests/RTC_Tests.ino: -------------------------------------------------------------------------------- 1 | /* 2 | RTC_Tests 3 | 4 | This sketch allows to test STM32RTC library API. 5 | 6 | Creation 25 Apr 2018 7 | by Frederic Pillon for STMicroelectronics 8 | 9 | This example code is in the public domain. 10 | 11 | https://github.com/stm32duino/STM32RTC 12 | 13 | */ 14 | 15 | #include 16 | 17 | /* Get the rtc object */ 18 | STM32RTC& rtc = STM32RTC::getInstance(); 19 | 20 | /* Change these values to set the current initial time 21 | 22 | format: date: "Dec 31 2017" and time: "23:59:56" 23 | by default use built date and time 24 | */ 25 | static const char* mydate = __DATE__; 26 | static const char* mytime = __TIME__; 27 | //static const char* mydate = "Dec 31 2017"; 28 | //static const char* mytime = "23:59:56"; 29 | 30 | /* Change these values to set user (a)synchronous prescalers 31 | value to test. 32 | 33 | Default 99/9999 are for RTCCLK = 1MHz 34 | Example for DISCO_F746NG with a HSE of 25MHz 35 | HSE divider will be 25 and RTCCLK will be 1MHz. (HSE/HSEdiv) 36 | 37 | To have a calendar clock of 1 Hz: 38 | clk = RTCCLK / ((predA +1) * (predS +1)) 39 | clk = 1000000 / ((99 +1) * (9999+1)) = 1 Hz 40 | */ 41 | #if defined(STM32F1xx) 42 | static uint32_t userPredA = 99; 43 | #else 44 | static int8_t userPredA = 99; 45 | #endif /* STM32F1xx */ 46 | static int16_t userPredS = 9999; 47 | 48 | /* */ 49 | static byte seconds = 0; 50 | static byte minutes = 0; 51 | static byte hours = 0; 52 | 53 | static byte weekDay = 1; 54 | static byte day = 0; 55 | static byte month = 0; 56 | static byte year = 0; 57 | 58 | static STM32RTC::Hour_Format hourFormat = STM32RTC::HOUR_24; 59 | static STM32RTC::AM_PM period = STM32RTC::AM; 60 | 61 | #ifndef STM32F1xx 62 | static STM32RTC::Alarm_Match SS_MATCH = STM32RTC::MATCH_SS; 63 | static STM32RTC::Alarm_Match MMSS_MATCH = STM32RTC::MATCH_MMSS; 64 | static STM32RTC::Alarm_Match HHMMSS_MATCH = STM32RTC::MATCH_HHMMSS; 65 | #endif 66 | static STM32RTC::Alarm_Match DHHMMSS_MATCH = STM32RTC::MATCH_DHHMMSS; 67 | 68 | void setup() 69 | { 70 | Serial.begin(115200); 71 | while (!Serial) {} 72 | } 73 | 74 | void loop() 75 | { 76 | int c; // Serial input 77 | STM32RTC::Source_Clock clkSource = rtc.LSI_CLOCK; 78 | 79 | // Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK. 80 | Serial.println("Select clock Source:"); 81 | Serial.println("1- LSI_CLOCK"); 82 | Serial.println("2- LSE_CLOCK"); 83 | Serial.println("3- HSE_CLOCK"); 84 | Serial.println(); 85 | // get input 86 | while (1) { 87 | while (Serial.read() >= 0) {} 88 | Serial.print("Enter number [1-3] "); 89 | while ((c = Serial.read()) < 0) {} 90 | Serial.println((char)c); 91 | if (c < '1' || c > '3') { 92 | Serial.println("Invalid input"); 93 | continue; 94 | } 95 | switch (c) { 96 | case '1': 97 | default: 98 | Serial.println("Test will use LSI_CLOCK"); 99 | clkSource = rtc.LSI_CLOCK; 100 | break; 101 | case '2': 102 | Serial.println("Test will use LSE_CLOCK"); 103 | clkSource = rtc.LSE_CLOCK; 104 | break; 105 | case '3': 106 | Serial.println("Test will use HSE_CLOCK"); 107 | clkSource = rtc.HSE_CLOCK; 108 | break; 109 | } 110 | break; 111 | } 112 | 113 | #if defined(STM32F1xx) 114 | Serial.println("Testing only asynchronous prescaler setting"); 115 | uint32_t a; 116 | #else 117 | Serial.println("Testing asynchronous and synchronous prescaler setting"); 118 | int8_t a; 119 | #endif /* STM32F1xx */ 120 | int16_t s = 0; 121 | rtc.getPrediv(&a, &s); 122 | Serial.print("Async/Sync for default LSI clock: "); 123 | Serial.printf("%i/%i\n", a, s); 124 | rtc_config(clkSource, rtc.HOUR_24, mydate, mytime); 125 | Serial.print("Async/Sync for selected clock: "); 126 | rtc.getPrediv(&a, &s); 127 | Serial.printf("%i/%i\n", a, s); 128 | rtc.end(); 129 | 130 | if (clkSource == rtc.HSE_CLOCK) { 131 | Serial.printf("User Async/Sync set to %i/%i:", userPredA, userPredS); 132 | rtc.setPrediv(userPredA, userPredS); 133 | rtc_config(clkSource, rtc.HOUR_24, mydate, mytime); 134 | rtc.getPrediv(&a, &s); 135 | Serial.printf("%i/%i\n", a, s); 136 | printDateTime(10, 1000, false); 137 | } 138 | 139 | Serial.print("User Async/Sync reset to use the computed one: "); 140 | rtc.setPrediv(-1, -1); 141 | rtc_config(clkSource, rtc.HOUR_24, mydate, mytime); 142 | rtc.getPrediv(&a, &s); 143 | Serial.printf("%i/%i\n", a, s); 144 | 145 | // Check date change 146 | Serial.println("Testing date and time"); 147 | Serial.println("24H format, new year"); 148 | rtc_config(clkSource, rtc.HOUR_24, "Dec 31 2017", "23:59:56"); 149 | printDateTime(8, 1000, false); 150 | Serial.println(); 151 | 152 | #ifndef STM32F1xx 153 | Serial.println("12H format, new year"); 154 | rtc_config(clkSource, rtc.HOUR_12, "Dec 31 2017", "23:59:56"); 155 | printDateTime(8, 1000, false); 156 | Serial.println(); 157 | 158 | Serial.println("12H format, from AM to PM"); 159 | rtc_config(clkSource, rtc.HOUR_12, "Dec 31 2017", "11:59:56"); 160 | printDateTime(8, 1000, false); 161 | Serial.println(); 162 | #endif //STM32F1xx 163 | 164 | Serial.println("Using Epoch API, set to Jan 1, 2016"); 165 | rtc.setEpoch(1451606400); // Jan 1, 2016 166 | for (uint32_t i = 0; i < 8; i++) { 167 | Serial.printf("Unix time = %u\n", rtc.getEpoch()); 168 | Serial.printf("Seconds since Jan 1 2000 = %u\n", rtc.getY2kEpoch()); 169 | printDateTime(1, 1000, false); 170 | } 171 | 172 | Serial.println("\nTesting alarm"); 173 | rtc_config(clkSource, rtc.HOUR_24, mydate, mytime); 174 | byte alarmSeconds = ((seconds + 5) < 60) ? seconds + 5 : 5; 175 | byte alarmMinutes = ((seconds + 5) < 60) ? minutes : ((minutes + 1) < 60) ? minutes + 1 : 0; 176 | byte alarmHours = ((seconds + 5) < 60) ? hours : ((minutes + 1) < 60) ? hours : ((hours + 1) < 24) ? hours + 1 : 0; 177 | byte alarmDay = (hours == alarmHours) ? day : ((day + 1) <= 31) ? day + 1 : 1; 178 | 179 | #if defined(STM32_RTC_VERSION) && (STM32_RTC_VERSION >= 0x01010000) 180 | rtc.setAlarmSubSeconds(123); 181 | #endif 182 | 183 | #ifndef STM32F1xx 184 | Serial.println("\nEvery minute"); 185 | rtc.attachInterrupt(alarmMatch, (void*)&SS_MATCH); 186 | rtc.setAlarmSeconds(alarmSeconds); 187 | rtc.enableAlarm(rtc.MATCH_SS); 188 | printDateTime(20, 1000, true); 189 | rtc.disableAlarm(); 190 | rtc.detachInterrupt(); 191 | 192 | Serial.println("\nEvery hours"); 193 | rtc_setTime(mydate, mytime); 194 | rtc.attachInterrupt(alarmMatch, (void*)&MMSS_MATCH); 195 | rtc.setAlarmMinutes(alarmMinutes); 196 | rtc.enableAlarm(rtc.MATCH_MMSS); 197 | printDateTime(20, 1000, true); 198 | rtc.disableAlarm(); 199 | rtc.detachInterrupt(); 200 | 201 | Serial.println("\nEvery day"); 202 | rtc_setTime(mydate, mytime); 203 | rtc.attachInterrupt(alarmMatch, (void*)&HHMMSS_MATCH); 204 | rtc.setAlarmHours(alarmHours); 205 | rtc.enableAlarm(rtc.MATCH_HHMMSS); 206 | printDateTime(20, 1000, true); 207 | rtc.disableAlarm(); 208 | rtc.detachInterrupt(); 209 | #endif // STM32F1xx 210 | 211 | Serial.println("\nEvery month"); 212 | rtc_setTime(mydate, mytime); 213 | rtc.attachInterrupt(alarmMatch, (void*)&DHHMMSS_MATCH); 214 | #if defined(STM32_RTC_VERSION) && (STM32_RTC_VERSION >= 0x01010000) 215 | rtc.setAlarmTime(alarmHours, alarmMinutes, alarmSeconds, 123); 216 | #else 217 | rtc.setAlarmTime(alarmHours, alarmMinutes, alarmSeconds); 218 | #endif 219 | rtc.setAlarmDay(alarmDay); 220 | rtc.enableAlarm(rtc.MATCH_DHHMMSS); 221 | printDateTime(20, 1000, true); 222 | rtc.disableAlarm(); 223 | rtc.detachInterrupt(); 224 | 225 | rtc_config(clkSource, rtc.HOUR_24, mydate, mytime); 226 | Serial.println("\nAlarm disabled. Printing each 10s."); 227 | printDateTime(-1, 10000, false); 228 | } 229 | 230 | void alarmMatch(void *data) 231 | { 232 | STM32RTC::Alarm_Match m = *(STM32RTC::Alarm_Match*)data; 233 | 234 | Serial.print("Alarm Match at "); 235 | printDateTime(1, 0, false); 236 | switch (m) { 237 | case STM32RTC::MATCH_OFF: 238 | Serial.println("MATCH_OFF could not happen"); 239 | break; 240 | case STM32RTC::MATCH_YYMMDDHHMMSS://kept for compatibility 241 | case STM32RTC::MATCH_MMDDHHMMSS: //kept for compatibility 242 | case STM32RTC::MATCH_DHHMMSS: 243 | Serial.println("MATCH_DHHMMSS"); 244 | rtc.setMonth(((rtc.getMonth() + 1) < 13) ? rtc.getMonth() + 1 : 1); 245 | rtc.setEpoch(rtc.getEpoch() - 10); 246 | break; 247 | case STM32RTC::MATCH_HHMMSS: 248 | Serial.println("MATCH_HHMMSS"); 249 | rtc.setEpoch(rtc.getEpoch() + 86395); 250 | break; 251 | case STM32RTC::MATCH_MMSS: 252 | Serial.println("MATCH_MMSS"); 253 | rtc.setEpoch(rtc.getEpoch() + 3595); 254 | break; 255 | case STM32RTC::MATCH_SS: 256 | Serial.println("MATCH_SS"); 257 | rtc.setEpoch(rtc.getEpoch() + 55); 258 | break; 259 | default: 260 | Serial.println("Unknown STM32RTC::Alarm_Match type"); 261 | break; 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /examples/NonReg/RTC/RTC_Tests/RTC_utils.ino: -------------------------------------------------------------------------------- 1 | 2 | static uint8_t conv2d(const char* p) { 3 | uint8_t v = 0; 4 | if ('0' <= *p && *p <= '9') 5 | v = *p - '0'; 6 | return 10 * v + *++p - '0'; 7 | } 8 | 9 | // sample input: date = "Dec 26 2009", time = "12:34:56" 10 | void initDateTime (const char* date, const char* time) { 11 | year = conv2d(date + 9); 12 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 13 | switch (date[0]) { 14 | case 'J': month = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7); break; 15 | case 'F': month = 2; break; 16 | case 'A': month = date[2] == 'r' ? 4 : 8; break; 17 | case 'M': month = date[2] == 'r' ? 3 : 5; break; 18 | case 'S': month = 9; break; 19 | case 'O': month = 10; break; 20 | case 'N': month = 11; break; 21 | case 'D': month = 12; break; 22 | } 23 | day = conv2d(date + 4); 24 | hours = conv2d(time); 25 | if (hourFormat == rtc.HOUR_12) { 26 | period = hours >= 12 ? rtc.PM : rtc.AM; 27 | hours = hours >= 13 ? hours - 12 : (hours < 1 ? hours + 12 : hours); 28 | } 29 | minutes = conv2d(time + 3); 30 | seconds = conv2d(time + 6); 31 | } 32 | 33 | // t: number of print 34 | // d: delay between each print 35 | // a: display alarm 36 | void printDateTime(uint32_t t, uint32_t d, bool a) { 37 | uint32_t subSeconds; 38 | 39 | for (uint32_t i = 0; i < t; i++) { 40 | rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period); 41 | 42 | // Print date... 43 | Serial.printf("%02d/%02d/%02d\t", rtc.getMonth(), rtc.getDay(), rtc.getYear()); 44 | 45 | // ...and time 46 | Serial.printf("%02d:%02d:%02d.%03d", hours, minutes, seconds, subSeconds); 47 | 48 | if (hourFormat == rtc.HOUR_12) { 49 | Serial.print(period == rtc.AM ? " AM" : " PM"); 50 | } 51 | if (a) { 52 | // Print day... 53 | Serial.printf("\t%02d\t", rtc.getAlarmDay()); 54 | // ...and time 55 | Serial.printf("%02d:%02d:%02d.%03d", rtc.getAlarmHours(&period), rtc.getAlarmMinutes(), 56 | rtc.getAlarmSeconds(), rtc.getAlarmSubSeconds()); 57 | if (hourFormat == rtc.HOUR_12) { 58 | Serial.print(period == rtc.AM ? " AM" : " PM"); 59 | } 60 | } 61 | Serial.println(); 62 | delay(d); 63 | } 64 | } -------------------------------------------------------------------------------- /examples/NonReg/SPI_loop/SPI_loop.ino: -------------------------------------------------------------------------------- 1 | /* 2 | SPI_loopback 3 | 4 | Test the loopback transfer on SPI. 5 | A single SPI instance is used, the default one. 6 | MISO pin must be externally connected to MOSI pin. 7 | To test the transfer on different SPI instance, just redefine SPI pins 8 | as follows: 9 | #define MOSI_PIN XXX 10 | #define SCK_PIN XXX 11 | #define MISO_PIN XXX 12 | #define CS_PIN XXX 13 | 14 | Test behavior: 15 | A test string is sent 9 times and compared to the Rx frame. 16 | The LED remains ON when test ends successfully 17 | The LED remains OFF in case of error. 18 | This example code is in the public domain. 19 | */ 20 | #include "SPI.h" 21 | 22 | #ifndef LED_BUILTIN 23 | #define LED_BUILTIN PNUM_NOT_DEFINED 24 | #warning "LED_BUILTIN is not defined." 25 | #endif 26 | 27 | /* Set to 1 if CS have to be managed by the hardware */ 28 | #define CS_HARDWARE_CONTROL 0 29 | 30 | #define MOSI_PIN PIN_SPI_MOSI 31 | #define MISO_PIN PIN_SPI_MISO 32 | #define SCK_PIN PIN_SPI_SCK 33 | #define CS_PIN PIN_SPI_SS 34 | 35 | uint8_t buffer_tx[] = "Thequickbrownfoxjumpsoverthelazydog\0"; 36 | #define BUF_SIZE sizeof(buffer_tx) 37 | uint8_t buffer_rx[BUF_SIZE] = {}; 38 | 39 | /* SPI transfer loop nb */ 40 | #define TEST_LOOP_NB 9 41 | 42 | void setup() { 43 | uint8_t tested_ok = 0; // test result 44 | 45 | SPI.setMOSI(MOSI_PIN); 46 | SPI.setMISO(MISO_PIN); 47 | SPI.setSCLK(SCK_PIN); 48 | #if CS_HARDWARE_CONTROL == 1 49 | SPI.setSSEL(CS_PIN); 50 | #endif 51 | #if CS_HARDWARE_CONTROL == 0 52 | pinMode(CS_PIN, OUTPUT); 53 | digitalWrite(CS_PIN, HIGH); 54 | #endif 55 | 56 | /* the SPI pin configuration is done by the SPI.begin */ 57 | SPI.begin(); 58 | 59 | for (uint8_t received = 0; received < TEST_LOOP_NB; received++) { 60 | #if CS_HARDWARE_CONTROL == 0 61 | digitalWrite(CS_PIN, LOW); 62 | #endif 63 | SPI.transfer(buffer_tx, buffer_rx, BUF_SIZE); 64 | #if CS_HARDWARE_CONTROL == 0 65 | digitalWrite(CS_PIN, HIGH); 66 | #endif 67 | /* compare what is received to what was sent */ 68 | if (!memcmp(buffer_tx, buffer_rx, BUF_SIZE)) { 69 | /* this transfer passed */ 70 | tested_ok++; 71 | } 72 | memset(buffer_rx, 0, BUF_SIZE); 73 | } 74 | /* display test result */ 75 | pinMode(LED_BUILTIN, OUTPUT); // Configure LED pin, for test result 76 | digitalWrite(LED_BUILTIN, LOW); // start with led off 77 | if (tested_ok == TEST_LOOP_NB) { 78 | /* success */ 79 | digitalWrite(LED_BUILTIN, HIGH); 80 | } else { 81 | /* error. Please verify MISO is externally connected to MOSI */ 82 | digitalWrite(LED_BUILTIN, LOW); 83 | } 84 | } 85 | 86 | void loop() { 87 | /* nothing to do */ 88 | } 89 | -------------------------------------------------------------------------------- /examples/NonReg/SerialLoop/SerialLoop.ino: -------------------------------------------------------------------------------- 1 | /* 2 | SerialLoop 3 | 4 | Test all hardware serial configs at several speeds 5 | by sending all possible data range and comparing Tx/Rx. 6 | 7 | Creation 10 Jul 2017 8 | by Frederic Pillon 9 | 10 | This example code is in the public domain. 11 | */ 12 | 13 | #include "utils.h" 14 | 15 | /* 16 | 1 - Connect Rx/Tx of the desired Serial 17 | 2 - Define UART_TEST_INSTANCE 18 | ! Ensure Serial feature is enabled thanks 'U(S)ART support menu'! 19 | 3 - Optionnal: comment unwanted speed in serialSpeed array. 20 | */ 21 | #define SERIAL_PORT_TESTED SerialTest 22 | #if defined(SERIAL_UART_INSTANCE) && (SERIAL_UART_INSTANCE != 1) && defined(USART1_BASE) 23 | #define UART_TEST_INSTANCE USART1 24 | #elif defined(SERIAL_UART_INSTANCE) && (SERIAL_UART_INSTANCE != 2) && defined(USART2_BASE) 25 | #define UART_TEST_INSTANCE USART2 26 | #else 27 | #define UART_TEST_INSTANCE LPUART1 28 | #endif 29 | // or 30 | //HardwareSerial Serialx(rxpin, txpin) 31 | HardwareSerial SERIAL_PORT_TESTED(UART_TEST_INSTANCE); 32 | 33 | #define DECL_CONFIG(x) {#x, x} 34 | 35 | typedef struct serialTest_s serialTest; 36 | struct serialTest_s { 37 | const char* name; 38 | uint32_t config; 39 | }; 40 | 41 | static serialTest serialConfig[] = { 42 | #ifdef UART_WORDLENGTH_7B 43 | DECL_CONFIG(SERIAL_7N1), 44 | DECL_CONFIG(SERIAL_7N2), 45 | DECL_CONFIG(SERIAL_6E1), 46 | DECL_CONFIG(SERIAL_6E2), 47 | DECL_CONFIG(SERIAL_6O1), 48 | DECL_CONFIG(SERIAL_6O2), 49 | #endif 50 | DECL_CONFIG(SERIAL_8N1), 51 | DECL_CONFIG(SERIAL_8N2), 52 | DECL_CONFIG(SERIAL_7E1), 53 | DECL_CONFIG(SERIAL_8E1), 54 | DECL_CONFIG(SERIAL_7E2), 55 | DECL_CONFIG(SERIAL_7O1), 56 | DECL_CONFIG(SERIAL_8O1), 57 | DECL_CONFIG(SERIAL_7O2), 58 | DECL_CONFIG(SERIAL_8O2), 59 | DECL_CONFIG(SERIAL_8E2) 60 | }; 61 | 62 | static uint32_t serialSpeed[] = { 63 | 300, 64 | 1200, 65 | 2400, 66 | 4800, 67 | 9600, 68 | 19200, 69 | 38400, 70 | 57600, 71 | 74880, 72 | 115200, 73 | 230400, 74 | 250000, 75 | 500000, 76 | 1000000, 77 | 2000000 78 | }; 79 | 80 | static uint32_t start_time = 0; 81 | static uint32_t configCur = 0; 82 | static uint32_t configNb = sizeof(serialConfig) / sizeof(serialTest); 83 | static uint32_t speedNb = sizeof(serialSpeed) / sizeof(uint32_t); 84 | static uint32_t nbTestOK = 0; 85 | static uint32_t nbTestKO = 0; 86 | 87 | uint32_t dataMask(uint32_t config) { 88 | uint32_t databits = 0; 89 | switch (config & 0x07) { 90 | case 0x02: 91 | databits = 6; 92 | break; 93 | case 0x04: 94 | databits = 7; 95 | break; 96 | case 0x06: 97 | databits = 8; 98 | break; 99 | default: 100 | databits = 0; 101 | break; 102 | } 103 | return ((1 << databits) - 1); 104 | } 105 | 106 | void test_uart(int val) 107 | { 108 | int recval = 0; 109 | SERIAL_PORT_TESTED.write(val); 110 | delay(10); 111 | while (SERIAL_PORT_TESTED.available()) { 112 | recval = SERIAL_PORT_TESTED.read(); 113 | } 114 | if (val == recval) { 115 | nbTestOK++; 116 | } 117 | else { 118 | SERIAL_PORT_MONITOR.print("Send: 0x"); 119 | SERIAL_PORT_MONITOR.print(val, HEX); 120 | SERIAL_PORT_MONITOR.print("\tReceived: 0x"); 121 | SERIAL_PORT_MONITOR.print(recval, HEX); 122 | SERIAL_PORT_MONITOR.println(" --> KO <--"); 123 | nbTestKO++; 124 | } 125 | } 126 | 127 | void setup() { 128 | SERIAL_PORT_MONITOR.begin(115200); 129 | while (!SERIAL_PORT_MONITOR); 130 | SERIAL_PORT_MONITOR.print("SerialLoop test on "); 131 | SERIAL_PORT_MONITOR.println(XSTR(SERIAL_PORT_TESTED)); 132 | SERIAL_PORT_MONITOR.print(configNb); 133 | SERIAL_PORT_MONITOR.println(" configs to test."); 134 | SERIAL_PORT_MONITOR.print(speedNb); 135 | SERIAL_PORT_MONITOR.println(" speed to test."); 136 | start_time = millis(); 137 | } 138 | 139 | void loop() { 140 | uint32_t mask = 0; 141 | if (configCur == configNb) { 142 | SERIAL_PORT_MONITOR.println("SerialLoop test done.\nResults:"); 143 | SERIAL_PORT_MONITOR.print("OK: "); 144 | SERIAL_PORT_MONITOR.println(nbTestOK); 145 | SERIAL_PORT_MONITOR.print("KO: "); 146 | SERIAL_PORT_MONITOR.println(nbTestKO); 147 | SERIAL_PORT_MONITOR.print("Test duration (ms): "); 148 | SERIAL_PORT_MONITOR.print(millis() - start_time); 149 | 150 | while (1); // End test 151 | } 152 | 153 | SERIAL_PORT_MONITOR.println("########################"); 154 | SERIAL_PORT_MONITOR.print("Config: "); 155 | SERIAL_PORT_MONITOR.print(serialConfig[configCur].name); 156 | SERIAL_PORT_MONITOR.print(" (0x"); 157 | SERIAL_PORT_MONITOR.print(serialConfig[configCur].config, HEX); 158 | SERIAL_PORT_MONITOR.println(")"); 159 | for (uint32_t s = 0; s < speedNb; s++) { 160 | SERIAL_PORT_MONITOR.print("Test at "); 161 | SERIAL_PORT_MONITOR.print(serialSpeed[s]); 162 | SERIAL_PORT_MONITOR.println(" baud"); 163 | SERIAL_PORT_TESTED.begin(serialSpeed[s], serialConfig[configCur].config); 164 | mask = dataMask(serialConfig[configCur].config); 165 | for (uint32_t i = 0; i <= (0xFF & mask); i++) 166 | { 167 | test_uart(i & mask); 168 | } 169 | SERIAL_PORT_TESTED.end(); 170 | } 171 | SERIAL_PORT_MONITOR.println("End."); 172 | configCur++; 173 | } 174 | -------------------------------------------------------------------------------- /examples/Peripherals/ADC/Internal_channels/Internal_channels.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Internal_channels 3 | This example shows how to read then convert to proper Unit the 3 internal channels + A0. 4 | 5 | analogRead() can now be used to read some internal channels with the following definitions: 6 | ATEMP: internal temperature sensor 7 | AVREF: VrefInt, internal voltage reference 8 | AVBAT: Vbat voltage 9 | 10 | A minimum ADC sampling time is required when reading internal channels 11 | so default is set it to max possible value. 12 | It can be defined more precisely by defining: 13 | ADC_SAMPLINGTIME_INTERNAL to the desired ADC sample time. 14 | 15 | ADC_SAMPLINGTIME and ADC_CLOCK_DIV could also be redefined by the variant or using build_opt.h. 16 | 17 | This example is provided "as it" and can require some update mainly for datasheet values. 18 | */ 19 | 20 | #include "stm32yyxx_ll_adc.h" 21 | 22 | /* Values available in datasheet */ 23 | #if defined(STM32C0xx) 24 | #define CALX_TEMP 30 25 | #else 26 | #define CALX_TEMP 25 27 | #endif 28 | 29 | #if defined(STM32C0xx) 30 | #define VTEMP 760 31 | #define AVG_SLOPE 2530 32 | #define VREFINT 1212 33 | #elif defined(STM32F1xx) 34 | #define VTEMP 1430 35 | #define AVG_SLOPE 4300 36 | #define VREFINT 1200 37 | #elif defined(STM32F2xx) || defined(STM32F4xx) 38 | #define VTEMP 760 39 | #define AVG_SLOPE 2500 40 | #define VREFINT 1210 41 | #endif 42 | 43 | /* Analog read resolution */ 44 | #define LL_ADC_RESOLUTION LL_ADC_RESOLUTION_12B 45 | #define ADC_RANGE 4096 46 | 47 | // the setup routine runs once when you press reset: 48 | void setup() { 49 | // initialize serial communication at 9600 bits per second: 50 | Serial.begin(9600); 51 | while (!Serial); 52 | analogReadResolution(12); 53 | } 54 | 55 | static int32_t readVref() 56 | { 57 | #ifdef STM32U0xx 58 | /* On some devices Internal voltage reference calibration value not programmed 59 | during production and return 0xFFFF. See errata sheet. */ 60 | if ((uint32_t)(*VREFINT_CAL_ADDR) == 0xFFFF) { 61 | return 3300U; 62 | } 63 | #endif 64 | #ifdef __LL_ADC_CALC_VREFANALOG_VOLTAGE 65 | #ifdef STM32U5xx 66 | return (__LL_ADC_CALC_VREFANALOG_VOLTAGE(ADC1, analogRead(AVREF), LL_ADC_RESOLUTION)); 67 | #else 68 | return (__LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_RESOLUTION)); 69 | #endif 70 | #else 71 | return (VREFINT * ADC_RANGE / analogRead(AVREF)); // ADC sample to mV 72 | #endif 73 | } 74 | 75 | #ifdef ATEMP 76 | static int32_t readTempSensor(int32_t VRef) 77 | { 78 | #ifdef __LL_ADC_CALC_TEMPERATURE 79 | #ifdef STM32U5xx 80 | return (__LL_ADC_CALC_TEMPERATURE(ADC1, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); 81 | #else 82 | return (__LL_ADC_CALC_TEMPERATURE(VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); 83 | #endif 84 | #elif defined(__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS) 85 | return (__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(AVG_SLOPE, VTEMP, CALX_TEMP, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); 86 | #else 87 | return 0; 88 | #endif 89 | } 90 | #endif 91 | 92 | static int32_t readVoltage(int32_t VRef, uint32_t pin) 93 | { 94 | #ifdef STM32U5xx 95 | return (__LL_ADC_CALC_DATA_TO_VOLTAGE(ADC1, VRef, analogRead(pin), LL_ADC_RESOLUTION)); 96 | #else 97 | return (__LL_ADC_CALC_DATA_TO_VOLTAGE(VRef, analogRead(pin), LL_ADC_RESOLUTION)); 98 | #endif 99 | } 100 | 101 | // The loop routine runs over and over again forever: 102 | void loop() { 103 | #if defined(ICACHE) && defined (HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED) 104 | bool icache_enabled = false; 105 | if (HAL_ICACHE_IsEnabled() == 1) { 106 | icache_enabled = true; 107 | /* Disable instruction cache prior to internal cacheable memory update */ 108 | if (HAL_ICACHE_Disable() != HAL_OK) { 109 | Error_Handler(); 110 | } 111 | } 112 | #endif /* ICACHE && HAL_ICACHE_MODULE_ENABLED && !HAL_ICACHE_MODULE_DISABLED */ 113 | // Print out the value read 114 | int32_t VRef = readVref(); 115 | Serial.printf("VRef(mv)= %i", VRef); 116 | #ifdef ATEMP 117 | Serial.printf("\tTemp(°C)= %i", readTempSensor(VRef)); 118 | #endif 119 | #ifdef AVBAT 120 | Serial.printf("\tVbat(mv)= %i", readVoltage(VRef, AVBAT)); 121 | #endif 122 | Serial.printf("\tA0(mv)= %i\n", readVoltage(VRef, A0)); 123 | delay(200); 124 | #if defined(ICACHE) && defined (HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED) 125 | if (icache_enabled) 126 | { 127 | /* Re-enable instruction cache */ 128 | if (HAL_ICACHE_Enable() != HAL_OK) { 129 | Error_Handler(); 130 | } 131 | } 132 | #endif /* ICACHE && HAL_ICACHE_MODULE_ENABLED && !HAL_ICACHE_MODULE_DISABLED */ 133 | } -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/All-in-one_setPWM/All-in-one_setPWM.ino: -------------------------------------------------------------------------------- 1 | /* 2 | All-in-one setPWM 3 | This example shows how to configure a PWM with HardwareTimer in one single function call. 4 | PWM is generated on `LED_BUILTIN` if available. 5 | No interruption callback used: PWM is generated by hardware. 6 | Once configured, there is no CPU load. 7 | */ 8 | 9 | /* 10 | Note: Please verify that 'pin' used for PWM has HardwareTimer capability for your board 11 | This is specially true for F1 serie (BluePill, ...) 12 | */ 13 | 14 | #if defined(LED_BUILTIN) 15 | #define pin LED_BUILTIN 16 | #else 17 | #define pin D2 18 | #endif 19 | 20 | void setup() 21 | { 22 | // no need to configure pin, it will be done by HardwareTimer configuration 23 | // pinMode(pin, OUTPUT); 24 | 25 | // Automatically retrieve TIM instance and channel associated to pin 26 | // This is used to be compatible with all STM32 series automatically. 27 | TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); 28 | uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); 29 | 30 | 31 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished. 32 | HardwareTimer *MyTim = new HardwareTimer(Instance); 33 | 34 | // Configure and start PWM 35 | // MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we can simplify the function call 36 | MyTim->setPWM(channel, pin, 5, 10); // 5 Hertz, 10% dutycycle 37 | } 38 | 39 | 40 | void loop() 41 | { 42 | /* Nothing to do all is done by hardware. Even no interrupt required. */ 43 | } -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/Frequency_Dutycycle_measurement/Frequency_Dutycycle_measurement.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Frequency and dutycycle measurement 3 | This example shows how to configure HardwareTimer to measure external signal frequency and dutycycle. 4 | The input pin will be connected to 2 channel of the timer, one for rising edge the other for falling edge. 5 | Each time a rising edge is detected on the input pin, hardware will save counter value into one of the CaptureCompare register. 6 | Each time a falling edge is detected on the input pin, hardware will save counter value into the other CaptureCompare register. 7 | External signal (signal generator for example) should be connected to `D2`. 8 | 9 | */ 10 | 11 | /* 12 | Note: Please verify that for your board,'pin' used for PWM has HardwareTimer capability 13 | This is specially true for F1 serie (BluePill, ...) 14 | */ 15 | 16 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 17 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 18 | #endif 19 | 20 | #define pin D2 21 | 22 | uint32_t channelRising, channelFalling; 23 | volatile uint32_t FrequencyMeasured, DutycycleMeasured, LastPeriodCapture = 0, CurrentCapture, HighStateMeasured; 24 | uint32_t input_freq = 0; 25 | volatile uint32_t rolloverCompareCount = 0; 26 | HardwareTimer *MyTim; 27 | 28 | /** 29 | @brief Input capture interrupt callback : Compute frequency and dutycycle of input signal 30 | 31 | */ 32 | void TIMINPUT_Capture_Rising_IT_callback(void) 33 | { 34 | CurrentCapture = MyTim->getCaptureCompare(channelRising); 35 | /* frequency computation */ 36 | if (CurrentCapture > LastPeriodCapture) 37 | { 38 | FrequencyMeasured = input_freq / (CurrentCapture - LastPeriodCapture); 39 | DutycycleMeasured = (HighStateMeasured * 100) / (CurrentCapture - LastPeriodCapture); 40 | } 41 | else if (CurrentCapture <= LastPeriodCapture) 42 | { 43 | /* 0x1000 is max overflow value */ 44 | FrequencyMeasured = input_freq / (0x10000 + CurrentCapture - LastPeriodCapture); 45 | DutycycleMeasured = (HighStateMeasured * 100) / (0x10000 + CurrentCapture - LastPeriodCapture); 46 | } 47 | 48 | LastPeriodCapture = CurrentCapture; 49 | rolloverCompareCount = 0; 50 | } 51 | 52 | /* In case of timer rollover, frequency is to low to be measured set values to 0 53 | To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. */ 54 | void Rollover_IT_callback(void) 55 | { 56 | rolloverCompareCount++; 57 | 58 | if (rolloverCompareCount > 1) 59 | { 60 | FrequencyMeasured = 0; 61 | DutycycleMeasured = 0; 62 | } 63 | } 64 | 65 | /** 66 | @brief Input capture interrupt callback : Compute frequency and dutycycle of input signal 67 | 68 | */ 69 | void TIMINPUT_Capture_Falling_IT_callback(void) 70 | { 71 | /* prepare DutyCycle computation */ 72 | CurrentCapture = MyTim->getCaptureCompare(channelFalling); 73 | 74 | if (CurrentCapture > LastPeriodCapture) 75 | { 76 | HighStateMeasured = CurrentCapture - LastPeriodCapture; 77 | } 78 | else if (CurrentCapture <= LastPeriodCapture) 79 | { 80 | /* 0x1000 is max overflow value */ 81 | HighStateMeasured = 0x10000 + CurrentCapture - LastPeriodCapture; 82 | } 83 | } 84 | 85 | 86 | void setup() 87 | { 88 | Serial.begin(115200); 89 | 90 | // Automatically retrieve TIM instance and channelRising associated to pin 91 | // This is used to be compatible with all STM32 series automatically. 92 | TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); 93 | channelRising = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); 94 | 95 | // channelRisings come by pair for TIMER_INPUT_FREQ_DUTY_MEASUREMENT mode: 96 | // channelRising1 is associated to channelFalling and channelRising3 is associated with channelRising4 97 | switch (channelRising) { 98 | case 1: 99 | channelFalling = 2; 100 | break; 101 | case 2: 102 | channelFalling = 1; 103 | break; 104 | case 3: 105 | channelFalling = 4; 106 | break; 107 | case 4: 108 | channelFalling = 3; 109 | break; 110 | } 111 | 112 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished. 113 | MyTim = new HardwareTimer(Instance); 114 | 115 | // Configure rising edge detection to measure frequency 116 | MyTim->setMode(channelRising, TIMER_INPUT_FREQ_DUTY_MEASUREMENT, pin); 117 | 118 | // With a PrescalerFactor = 1, the minimum frequency value to measure is : TIM counter clock / CCR MAX 119 | // = (SystemCoreClock) / 65535 120 | // Example on Nucleo_L476RG with systemClock at 80MHz, the minimum frequency is around 1,2 khz 121 | // To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. 122 | // The maximum frequency depends on processing of both interruptions and thus depend on board used 123 | // Example on Nucleo_L476RG with systemClock at 80MHz the interruptions processing is around 10 microseconds and thus Max frequency is around 100kHz 124 | uint32_t PrescalerFactor = 1; 125 | MyTim->setPrescaleFactor(PrescalerFactor); 126 | MyTim->setOverflow(0x10000); // Max Period value to have the largest possible time to detect rising edge and avoid timer rollover 127 | MyTim->attachInterrupt(channelRising, TIMINPUT_Capture_Rising_IT_callback); 128 | MyTim->attachInterrupt(channelFalling, TIMINPUT_Capture_Falling_IT_callback); 129 | MyTim->attachInterrupt(Rollover_IT_callback); 130 | 131 | MyTim->resume(); 132 | 133 | // Compute this scale factor only once 134 | input_freq = MyTim->getTimerClkFreq() / MyTim->getPrescaleFactor(); 135 | } 136 | 137 | 138 | void loop() 139 | { 140 | /* Print frequency and dutycycle measured on Serial monitor every seconds */ 141 | Serial.print((String)"Frequency = " + FrequencyMeasured); 142 | Serial.println((String)" Dutycycle = " + DutycycleMeasured); 143 | delay(1000); 144 | } -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/InputCapture/InputCapture.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Input capture 3 | This example shows how to configure HardwareTimer in inputcapture to measure external signal frequency. 4 | Each time a rising edge is detected on the input pin, hardware will save counter value into CaptureCompare register. 5 | External signal (signal generator for example) should be connected to `D2`. 6 | Measured frequency is displayed on Serial Monitor. 7 | */ 8 | 9 | /* 10 | Note: Please verify that 'pin' used for PWM has HardwareTimer capability for your board 11 | This is specially true for F1 serie (BluePill, ...) 12 | */ 13 | 14 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 15 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 16 | #endif 17 | 18 | #define pin D2 19 | 20 | uint32_t channel; 21 | volatile uint32_t FrequencyMeasured, LastCapture = 0, CurrentCapture; 22 | uint32_t input_freq = 0; 23 | volatile uint32_t rolloverCompareCount = 0; 24 | HardwareTimer *MyTim; 25 | 26 | void InputCapture_IT_callback(void) 27 | { 28 | CurrentCapture = MyTim->getCaptureCompare(channel); 29 | /* frequency computation */ 30 | if (CurrentCapture > LastCapture) { 31 | FrequencyMeasured = input_freq / (CurrentCapture - LastCapture); 32 | } 33 | else if (CurrentCapture <= LastCapture) { 34 | /* 0x1000 is max overflow value */ 35 | FrequencyMeasured = input_freq / (0x10000 + CurrentCapture - LastCapture); 36 | } 37 | LastCapture = CurrentCapture; 38 | rolloverCompareCount = 0; 39 | } 40 | 41 | /* In case of timer rollover, frequency is to low to be measured set value to 0 42 | To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. */ 43 | void Rollover_IT_callback(void) 44 | { 45 | rolloverCompareCount++; 46 | 47 | if (rolloverCompareCount > 1) 48 | { 49 | FrequencyMeasured = 0; 50 | } 51 | 52 | } 53 | 54 | void setup() 55 | { 56 | Serial.begin(115200); 57 | 58 | // Automatically retrieve TIM instance and channel associated to pin 59 | // This is used to be compatible with all STM32 series automatically. 60 | TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); 61 | channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); 62 | 63 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished. 64 | MyTim = new HardwareTimer(Instance); 65 | 66 | // Configure rising edge detection to measure frequency 67 | MyTim->setMode(channel, TIMER_INPUT_CAPTURE_RISING, pin); 68 | 69 | // With a PrescalerFactor = 1, the minimum frequency value to measure is : TIM counter clock / CCR MAX 70 | // = (SystemCoreClock) / 65535 71 | // Example on Nucleo_L476RG with systemClock at 80MHz, the minimum frequency is around 1,2 khz 72 | // To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. 73 | // The maximum frequency depends on processing of the interruption and thus depend on board used 74 | // Example on Nucleo_L476RG with systemClock at 80MHz the interruption processing is around 4,5 microseconds and thus Max frequency is around 220kHz 75 | uint32_t PrescalerFactor = 1; 76 | MyTim->setPrescaleFactor(PrescalerFactor); 77 | MyTim->setOverflow(0x10000); // Max Period value to have the largest possible time to detect rising edge and avoid timer rollover 78 | MyTim->attachInterrupt(channel, InputCapture_IT_callback); 79 | MyTim->attachInterrupt(Rollover_IT_callback); 80 | MyTim->resume(); 81 | 82 | // Compute this scale factor only once 83 | input_freq = MyTim->getTimerClkFreq() / MyTim->getPrescaleFactor(); 84 | } 85 | 86 | 87 | void loop() 88 | { 89 | /* Print frequency measured on Serial monitor every seconds */ 90 | Serial.println((String)"Frequency = " + FrequencyMeasured); 91 | delay(1000); 92 | } -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/PWM_FullConfiguration/PWM_FullConfiguration.ino: -------------------------------------------------------------------------------- 1 | /* 2 | PWM full configuration 3 | This example shows how to fully configure a PWM with HardwareTimer. 4 | PWM is generated on `LED_BUILTIN` if available. 5 | PWM is generated by hardware: no CPU load. 6 | Nevertheless, in this example both interruption callback are used on Compare match (Falling edge of PWM1 mode) and update event (rising edge of PWM1 mode). 7 | Those call back are used to toggle a second pin: `pin2`. 8 | Once configured, there is only CPU load for callbacks executions. 9 | */ 10 | 11 | /* 12 | Note: Please verify that 'pin' used for PWM has HardwareTimer capability for your board 13 | This is specially true for F1 serie (BluePill, ...) 14 | */ 15 | 16 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 17 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 18 | #endif 19 | 20 | // 'pin' PWM will be managed automatically by hardware whereas 'pin2' PWM will be managed by software through interrupt callback 21 | #if defined(LED_BUILTIN) 22 | #define pin LED_BUILTIN 23 | 24 | #if LED_BUILTIN == D3 25 | #define pin2 D2 26 | #else 27 | #define pin2 D3 28 | #endif 29 | 30 | #else 31 | #define pin D2 32 | #define pin2 D3 33 | #endif 34 | 35 | void Update_IT_callback(void) 36 | { // Update event correspond to Rising edge of PWM when configured in PWM1 mode 37 | digitalWrite(pin2, LOW); // pin2 will be complementary to pin 38 | } 39 | 40 | void Compare_IT_callback(void) 41 | { // Compare match event correspond to falling edge of PWM when configured in PWM1 mode 42 | digitalWrite(pin2, HIGH); 43 | } 44 | 45 | void setup() 46 | { 47 | // No need to configure pin, it will be done by HardwareTimer configuration 48 | // pinMode(pin, OUTPUT); 49 | 50 | // Need to configure pin2, as it is not managed by HardwareTimer 51 | pinMode(pin2, OUTPUT); 52 | 53 | // Automatically retrieve TIM instance and channel associated to pin 54 | // This is used to be compatible with all STM32 series automatically. 55 | TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); 56 | uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); 57 | 58 | 59 | // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup function is finished. 60 | HardwareTimer *MyTim = new HardwareTimer(Instance); 61 | 62 | MyTim->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin); 63 | // MyTim->setPrescaleFactor(8); // Due to setOverflow with MICROSEC_FORMAT, prescaler will be computed automatically based on timer input clock 64 | MyTim->setOverflow(100000, MICROSEC_FORMAT); // 100000 microseconds = 100 milliseconds 65 | MyTim->setCaptureCompare(channel, 50, PERCENT_COMPARE_FORMAT); // 50% 66 | MyTim->attachInterrupt(Update_IT_callback); 67 | MyTim->attachInterrupt(channel, Compare_IT_callback); 68 | MyTim->resume(); 69 | } 70 | 71 | 72 | void loop() 73 | { 74 | /* Nothing to do all is done by hardware. Even no interrupt required. */ 75 | } 76 | -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/Timebase_callback/Timebase_callback.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Timebase callback 3 | This example shows how to configure HardwareTimer to execute a callback at regular interval. 4 | Callback toggles pin. 5 | Once configured, there is only CPU load for callbacks executions. 6 | */ 7 | 8 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 9 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 10 | #endif 11 | 12 | #if defined(LED_BUILTIN) 13 | #define pin LED_BUILTIN 14 | #else 15 | #define pin D2 16 | #endif 17 | 18 | void Update_IT_callback(void) 19 | { // Toggle pin. 10hz toogle --> 5Hz PWM 20 | digitalWrite(pin, !digitalRead(pin)); 21 | } 22 | 23 | 24 | void setup() 25 | { 26 | #if defined(TIM1) 27 | TIM_TypeDef *Instance = TIM1; 28 | #else 29 | TIM_TypeDef *Instance = TIM2; 30 | #endif 31 | 32 | // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. 33 | HardwareTimer *MyTim = new HardwareTimer(Instance); 34 | 35 | // configure pin in output mode 36 | pinMode(pin, OUTPUT); 37 | 38 | MyTim->setOverflow(10, HERTZ_FORMAT); // 10 Hz 39 | MyTim->attachInterrupt(Update_IT_callback); 40 | MyTim->resume(); 41 | } 42 | 43 | 44 | void loop() 45 | { 46 | /* Nothing to do all is done by hardware. Even no interrupt required. */ 47 | } -------------------------------------------------------------------------------- /examples/Peripherals/HardwareTimer/Timebase_callback_with_parameter/Timebase_callback_with_parameter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Timebase callback 3 | This example shows how to configure HardwareTimer to execute a callback with some parameter at regular interval. 4 | Callback toggles pin. 5 | Once configured, there is only CPU load for callbacks executions. 6 | */ 7 | 8 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01090000) 9 | #error "Due to API change, this sketch is compatible with STM32_CORE_VERSION >= 0x01090000" 10 | #endif 11 | 12 | #if defined(LED_BUILTIN) 13 | #define pin LED_BUILTIN 14 | #else 15 | #define pin D2 16 | #endif 17 | 18 | 19 | uint32_t MyData = 1; // Parameter used for callback is arbitrarily a pointer to uint32_t, it could be of other type. 20 | 21 | // Every second, print on serial MyData. And increment it. 22 | void Update_IT_callback(uint32_t* data) 23 | { 24 | Serial.println(*data); 25 | *data = *data + 1; 26 | } 27 | 28 | void setup() 29 | { 30 | Serial.begin(9600); 31 | #if defined(TIM1) 32 | TIM_TypeDef *Instance = TIM1; 33 | #else 34 | TIM_TypeDef *Instance = TIM2; 35 | #endif 36 | 37 | // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. 38 | HardwareTimer *MyTim = new HardwareTimer(Instance); 39 | 40 | // configure pin in output mode 41 | pinMode(pin, OUTPUT); 42 | 43 | MyTim->setOverflow(1, HERTZ_FORMAT); // 1 Hz 44 | MyTim->attachInterrupt(std::bind(Update_IT_callback, &MyData)); // bind argument to callback: When Update_IT_callback is called MyData will be given as argument 45 | MyTim->resume(); 46 | } 47 | 48 | 49 | void loop() 50 | { 51 | /* Nothing to do all is done by hardware. Even no interrupt required. */ 52 | } -------------------------------------------------------------------------------- /img/dashboard_adafruit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stm32duino/STM32Examples/33f94a16b712c74ba2f8a9666c43bf1d6be28b7b/img/dashboard_adafruit.png -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=STM32duino Examples 2 | version=1.2.5 3 | author=several 4 | maintainer=stm32duino 5 | sentence=Provides several examples for the Arduino core for STM32 MCUs. 6 | paragraph=Arduino STM32 core, libraries and examples are available here: https://github.com/stm32duino 7 | category=Other 8 | url=https://github.com/stm32duino/STM32Examples 9 | architectures=stm32 10 | -------------------------------------------------------------------------------- /src/STM32Examples.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stm32duino/STM32Examples/33f94a16b712c74ba2f8a9666c43bf1d6be28b7b/src/STM32Examples.h --------------------------------------------------------------------------------