diff --git a/examples/NonReg/HardwareTimer/HardwareTimer_OutputInput_test/HardwareTimer_OutputInput_test.ino b/examples/NonReg/HardwareTimer/HardwareTimer_OutputInput_test/HardwareTimer_OutputInput_test.ino index 12a499b..1dc20d3 100644 --- a/examples/NonReg/HardwareTimer/HardwareTimer_OutputInput_test/HardwareTimer_OutputInput_test.ino +++ b/examples/NonReg/HardwareTimer/HardwareTimer_OutputInput_test/HardwareTimer_OutputInput_test.ino @@ -453,7 +453,7 @@ void loop() test_step++; MyTim_output->pauseChannel(Output1_channel); - MyTim_output->setMode(Output1_channel, TIMER_DISABLED); + MyTim_output->setMode(Output1_channel, TIMER_OUTPUT_DISABLED); MyTim_output->resumeChannel(Output1_channel); Verify_output(1, 0, 0); // in PWM2, output is the complementary of PW1 Verify_output(2, OUTPUT_FREQUENCY, OUTPUT_DUTY2); diff --git a/examples/NonReg/SPI_loop/SPI_loop.ino b/examples/NonReg/SPI_loop/SPI_loop.ino index 7feab8b..ae77e68 100644 --- a/examples/NonReg/SPI_loop/SPI_loop.ino +++ b/examples/NonReg/SPI_loop/SPI_loop.ino @@ -24,34 +24,46 @@ #warning "LED_BUILTIN is not defined." #endif -#define MOSI_PIN PIN_SPI_MOSI -#define MISO_PIN PIN_SPI_MISO -#define SCK_PIN PIN_SPI_SCK -#define CS_PIN PIN_SPI_SS +/* Set to 1 if CS have to be managed by the hardware */ +#define CS_HARDWARE_CONTROL 0 + +#define MOSI_PIN PIN_SPI_MOSI +#define MISO_PIN PIN_SPI_MISO +#define SCK_PIN PIN_SPI_SCK +#define CS_PIN PIN_SPI_SS uint8_t buffer_tx[] = "Thequickbrownfoxjumpsoverthelazydog\0"; -#define BUF_SIZE sizeof(buffer_tx) +#define BUF_SIZE sizeof(buffer_tx) uint8_t buffer_rx[BUF_SIZE] = {}; /* SPI transfer loop nb */ #define TEST_LOOP_NB 9 void setup() { - uint8_t tested_ok = 0; // test result + uint8_t tested_ok = 0; // test result SPI.setMOSI(MOSI_PIN); SPI.setMISO(MISO_PIN); SPI.setSCLK(SCK_PIN); - // Don't set CS_PIN to have Software ChipSelect management - // Instead, CS_PIN is passed as argument to SPI.transfer(CS_PIN) - // SPI.setSSEL(CS_PIN); +#if CS_HARDWARE_CONTROL == 1 + SPI.setSSEL(CS_PIN); +#endif +#if CS_HARDWARE_CONTROL == 0 + pinMode(CS_PIN, OUTPUT); + digitalWrite(CS_PIN, HIGH); +#endif /* the SPI pin configuration is done by the SPI.begin */ - SPI.begin(CS_PIN); + SPI.begin(); for (uint8_t received = 0; received < TEST_LOOP_NB; received++) { - SPI.transfer(CS_PIN, buffer_tx, buffer_rx, BUF_SIZE, SPI_LAST); - +#if CS_HARDWARE_CONTROL == 0 + digitalWrite(CS_PIN, LOW); +#endif + SPI.transfer(buffer_tx, buffer_rx, BUF_SIZE); +#if CS_HARDWARE_CONTROL == 0 + digitalWrite(CS_PIN, HIGH); +#endif /* compare what is received to what was sent */ if (!memcmp(buffer_tx, buffer_rx, BUF_SIZE)) { /* this transfer passed */ @@ -60,14 +72,14 @@ void setup() { memset(buffer_rx, 0, BUF_SIZE); } /* display test result */ - pinMode(LED_BUILTIN, OUTPUT); // Configure LED pin, for test result - digitalWrite(LED_BUILTIN, LOW); // start with led off + pinMode(LED_BUILTIN, OUTPUT); // Configure LED pin, for test result + digitalWrite(LED_BUILTIN, LOW); // start with led off if (tested_ok == TEST_LOOP_NB) { - /* success */ - digitalWrite(LED_BUILTIN, HIGH); + /* success */ + digitalWrite(LED_BUILTIN, HIGH); } else { - /* error. Please verify MISO is externally connected to MOSI */ - digitalWrite(LED_BUILTIN, LOW); + /* error. Please verify MISO is externally connected to MOSI */ + digitalWrite(LED_BUILTIN, LOW); } } diff --git a/examples/Peripherals/ADC/Internal_channels/Internal_channels.ino b/examples/Peripherals/ADC/Internal_channels/Internal_channels.ino index 7abcec3..73df14a 100644 --- a/examples/Peripherals/ADC/Internal_channels/Internal_channels.ino +++ b/examples/Peripherals/ADC/Internal_channels/Internal_channels.ino @@ -20,61 +20,89 @@ #include "stm32yyxx_ll_adc.h" /* Values available in datasheet */ +#if defined(STM32C0xx) +#define CALX_TEMP 30 +#else #define CALX_TEMP 25 -#if defined(STM32F1xx) -#define V25 1430 +#endif + +#if defined(STM32C0xx) +#define VTEMP 760 +#define AVG_SLOPE 2530 +#define VREFINT 1212 +#elif defined(STM32F1xx) +#define VTEMP 1430 #define AVG_SLOPE 4300 -#define VREFINT 1200 +#define VREFINT 1200 #elif defined(STM32F2xx) || defined(STM32F4xx) -#define V25 760 +#define VTEMP 760 #define AVG_SLOPE 2500 -#define VREFINT 1210 +#define VREFINT 1210 #endif /* Analog read resolution */ +#if defined(LL_ADC_RESOLUTION_12B) #define LL_ADC_RESOLUTION LL_ADC_RESOLUTION_12B +#elif defined(LL_ADC_DS_DATA_WIDTH_12_BIT) +#define LL_ADC_RESOLUTION LL_ADC_DS_DATA_WIDTH_12_BIT +#else +#error "ADC resolution could not be defined!" +#endif #define ADC_RANGE 4096 // the setup routine runs once when you press reset: void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); - while (!Serial); + while (!Serial) + ; analogReadResolution(12); } -static int32_t readVref() -{ +#ifdef AVREF +static uint32_t readVref() { + uint32_t Vref = 3300; +#ifdef STM32U0xx + /* On some devices Internal voltage reference calibration value not programmed + during production and return 0xFFFF. See errata sheet. */ + if ((uint32_t)(*VREFINT_CAL_ADDR) != 0xFFFF) { +#endif #ifdef __LL_ADC_CALC_VREFANALOG_VOLTAGE #ifdef STM32U5xx - return (__LL_ADC_CALC_VREFANALOG_VOLTAGE(ADC1, analogRead(AVREF), LL_ADC_RESOLUTION)); + Vref = __LL_ADC_CALC_VREFANALOG_VOLTAGE(ADC1, analogRead(AVREF), LL_ADC_RESOLUTION); #else - return (__LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_RESOLUTION)); + Vref = __LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_RESOLUTION); #endif #else - return (VREFINT * ADC_RANGE / analogRead(AVREF)); // ADC sample to mV + Vref = VREFINT * ADC_RANGE / analogRead(AVREF); // ADC sample to mV #endif +#ifdef STM32U0xx + } +#endif + return Vref; } +#endif #ifdef ATEMP -static int32_t readTempSensor(int32_t VRef) -{ +static int32_t readTempSensor(int32_t VRef) { + uint32_t temp = 0; #ifdef __LL_ADC_CALC_TEMPERATURE #ifdef STM32U5xx - return (__LL_ADC_CALC_TEMPERATURE(ADC1, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); + temp = __LL_ADC_CALC_TEMPERATURE(ADC1, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION); +#elif defined(STM32WB0x) + (void)VRef; + temp = __LL_ADC_CALC_TEMPERATURE(analogRead(ATEMP), LL_ADC_DS_DATA_WIDTH_12_BIT); #else - return (__LL_ADC_CALC_TEMPERATURE(VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); + temp = __LL_ADC_CALC_TEMPERATURE(VRef, analogRead(ATEMP), LL_ADC_RESOLUTION); #endif #elif defined(__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS) - return (__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(AVG_SLOPE, V25, CALX_TEMP, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION)); -#else - return 0; + temp = __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(AVG_SLOPE, VTEMP, CALX_TEMP, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION); #endif + return temp; } #endif -static int32_t readVoltage(int32_t VRef, uint32_t pin) -{ +static int32_t readVoltage(int32_t VRef, uint32_t pin) { #ifdef STM32U5xx return (__LL_ADC_CALC_DATA_TO_VOLTAGE(ADC1, VRef, analogRead(pin), LL_ADC_RESOLUTION)); #else @@ -84,9 +112,25 @@ static int32_t readVoltage(int32_t VRef, uint32_t pin) // The loop routine runs over and over again forever: void loop() { +#if defined(ICACHE) && defined(HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED) + bool icache_enabled = false; + if (HAL_ICACHE_IsEnabled() == 1) { + icache_enabled = true; + /* Disable instruction cache prior to internal cacheable memory update */ + if (HAL_ICACHE_Disable() != HAL_OK) { + Error_Handler(); + } + } +#endif /* ICACHE && HAL_ICACHE_MODULE_ENABLED && !HAL_ICACHE_MODULE_DISABLED */ + // Print out the value read +#ifdef AVREF int32_t VRef = readVref(); Serial.printf("VRef(mv)= %i", VRef); +#else + // No Vref fro STM32WB0xx + int32_t VRef = LL_ADC_VIN_RANGE_3V6; +#endif #ifdef ATEMP Serial.printf("\tTemp(°C)= %i", readTempSensor(VRef)); #endif @@ -95,4 +139,12 @@ void loop() { #endif Serial.printf("\tA0(mv)= %i\n", readVoltage(VRef, A0)); delay(200); +#if defined(ICACHE) && defined(HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED) + if (icache_enabled) { + /* Re-enable instruction cache */ + if (HAL_ICACHE_Enable() != HAL_OK) { + Error_Handler(); + } + } +#endif /* ICACHE && HAL_ICACHE_MODULE_ENABLED && !HAL_ICACHE_MODULE_DISABLED */ } \ No newline at end of file diff --git a/examples/Peripherals/Registers/Reset_reason/Reset_reason.ino b/examples/Peripherals/Registers/Reset_reason/Reset_reason.ino new file mode 100644 index 0000000..15179d0 --- /dev/null +++ b/examples/Peripherals/Registers/Reset_reason/Reset_reason.ino @@ -0,0 +1,123 @@ +/* Last Reset Reason Sketch +* This sketch will determine what caused the last reset on the STM32 MCU. Most microcontrollers +* have a register dedicated to storing the last reason of the chip, weather being from a +* low power condition, software caused or brown-out. Test it by resetting the MCU via holding the USER button, +* which triggers the Reset_my_MCU() function or unplug the USB cable and repluggit back. Adjust your +* UART, USER Button pin and registers accordingly. Use the MCU's datasheet and/or stm32yyyxxx.h for reference. +* The code is provided "as is" with no liability. +*/ + +#include "stm32yyxx_ll_rcc.h" +#include "IWatchdog.h" +// #include "STM32LowPower.h" + +#define USER_BTN_PIN USER_BTN // Adjust this for your board + +// Enumerator for combining reset flag bits into one byte then display them +enum reset_reason { + UNKNOWN_RESET = 0, + BROWN_OUT = 1 << 0, + NRST_PIN = 1 << 1, + SOFTWARE_RST = 1 << 2, + INDEPENDENT_WDG = 1 << 3, + WINDOW_WDG = 1 << 4, + LOW_POWER = 1 << 5, + OPTION_BYTE_LOADER = 1 << 6, + POWER_ON_DOWN = 1 << 7, + STANDBY = 1 << 8, + WAKEUP = 1 << 9 +}; + +reset_reason last_reset_reason = UNKNOWN_RESET; //is initially 0 or unknown +static int default_button_state = LOW; + +void Reset_My_MCU() { + // There are a few reset conditions. Keep the one you wish to use and comment out the others. + + // Below is the WakeUp reset condition (needs STM32LowPower.h library) + // LowPower.shutdown(1000); + + // Below is the Software reset condition + // NVIC_SystemReset(); + + // Below is the Watchdog Timer reset condition + IWatchdog.begin(1000); //1ms tick then reset + while (1) + ; // Wait for reset +} + +void setup() { + pinMode(USER_BTN_PIN, INPUT); + default_button_state = digitalRead(USER_BTN_PIN); + Serial.begin(115200); + while (!Serial) + ; // Wait for Serial + +#ifdef RCC_CSR_BORRSTF + if (LL_RCC_IsActiveFlag_BORRST()) last_reset_reason = (reset_reason)(last_reset_reason | BROWN_OUT); +#endif + if (LL_RCC_IsActiveFlag_PINRST()) last_reset_reason = (reset_reason)(last_reset_reason | NRST_PIN); + if (LL_RCC_IsActiveFlag_SFTRST()) last_reset_reason = (reset_reason)(last_reset_reason | SOFTWARE_RST); +#if defined(RCC_RSR_IWDG1RSTF) + if (LL_RCC_IsActiveFlag_IWDG1RST()) last_reset_reason = (reset_reason)(last_reset_reason | INDEPENDENT_WDG); +#else + if (LL_RCC_IsActiveFlag_IWDGRST()) last_reset_reason = (reset_reason)(last_reset_reason | INDEPENDENT_WDG); +#endif +#if defined(RCC_RSR_WWDG1RSTF) + if (LL_RCC_IsActiveFlag_WWDG1RST()) last_reset_reason = (reset_reason)(last_reset_reason | WINDOW_WDG); +#else + if (LL_RCC_IsActiveFlag_WWDGRST()) last_reset_reason = (reset_reason)(last_reset_reason | WINDOW_WDG); +#endif + if (LL_RCC_IsActiveFlag_LPWRRST()) last_reset_reason = (reset_reason)(last_reset_reason | LOW_POWER); +#if defined(RCC_CSR_OBLRSTF) || defined(RCC_CSR2_OBLRSTF) + if (LL_RCC_IsActiveFlag_OBLRST()) last_reset_reason = (reset_reason)(last_reset_reason | OPTION_BYTE_LOADER); +#endif +#ifdef RCC_CSR_PORRSTF + if (LL_RCC_IsActiveFlag_PORRST()) last_reset_reason = (reset_reason)(last_reset_reason | POWER_ON_DOWN); +#endif +#if defined(PWR_CSR_SBF) || defined(PWR_SR_SBF) || defined(PWR_SR1_SBF) || defined(PWR_CSR1_SBF) || defined(PWR_PMSR_SBF) + if (LL_PWR_IsActiveFlag_SB()) last_reset_reason = (reset_reason)(last_reset_reason | STANDBY); +#endif +#if defined(PWR_CSR_WUF) + if (LL_PWR_IsActiveFlag_WU()) last_reset_reason = (reset_reason)(last_reset_reason | WAKEUP); +#endif + + + // Clear internal reset flags after they were captured + LL_RCC_ClearResetFlags(); +#if defined(PWR_SCR_CSBF) || defined(PWR_CR1_CSBF) || defined(PWR_PMCR_CSSF) || defined(PWR_SR_CSSF) +#if defined(STM32U0xx) + LL_PWR_ClearFlag_CSB(); +#else + LL_PWR_ClearFlag_SB(); +#endif +#endif +#if defined(PWR_CSR_WUF) + LL_PWR_ClearFlag_WU(); +#endif +} + +void loop() { + Serial.println("Last reset reason:"); + + if (last_reset_reason & BROWN_OUT) Serial.println(" - Brown-out reset"); + if (last_reset_reason & SOFTWARE_RST) Serial.println(" - Software reset"); + if (last_reset_reason & INDEPENDENT_WDG) Serial.println(" - Independent Watchdog reset"); + if (last_reset_reason & WINDOW_WDG) Serial.println(" - Window Watchdog reset"); + if (last_reset_reason & LOW_POWER) Serial.println(" - Low-power reset"); + if (last_reset_reason & OPTION_BYTE_LOADER) Serial.println(" - Option byte loader reset"); + if (last_reset_reason & STANDBY) Serial.println(" - Standby mode reset"); + if (last_reset_reason & WAKEUP) Serial.println(" - WakeUp flag reset (Pin or RTC)"); + if (last_reset_reason & POWER_ON_DOWN) Serial.println(" - Power on or power down reset"); + if (last_reset_reason & NRST_PIN) Serial.println(" - Pin reset (NRST or software)"); //last case so the rest take precedence before issuing NRST + if (last_reset_reason == UNKNOWN_RESET) Serial.println(" - Unknown or no flags set"); + + // Trigger software reset on button press + if (digitalRead(USER_BTN_PIN) != default_button_state) { + Serial.println("Button pressed → Triggering reset..."); + delay(300); // Debounce + Reset_My_MCU(); + } + + delay(1000); +} diff --git a/examples/Peripherals/Registers/UID_Retrieve/UID_Retrieve.ino b/examples/Peripherals/Registers/UID_Retrieve/UID_Retrieve.ino new file mode 100644 index 0000000..605502a --- /dev/null +++ b/examples/Peripherals/Registers/UID_Retrieve/UID_Retrieve.ino @@ -0,0 +1,53 @@ +/* UID Retrieve sketch +* UID (Universal Identifier) is a ID that's etched to each MCU at factory release +* so it's uniquely identifiable. This can help traceability and addressing devices +* without having to craft a database yourself. This sketch retrieves UID, MAC, Device +* and Revision ID of each MCU. Refer to the relevant datasheet to know where are these +* values are stored in the registers. +* The code is provided "as is" with no liability. +*/ + +void setup() { + Serial.begin(115200); + while (!Serial) + ; // Wait for Serial to be ready + + Serial.printf("%s Device Identifiers:\n", BOARD_NAME); + + // Unique Device ID (96 bits / 12 bytes) + uint32_t uid0 = HAL_GetUIDw0(); + uint32_t uid1 = HAL_GetUIDw1(); + uint32_t uid2 = HAL_GetUIDw2(); + + Serial.print("UID: "); + Serial.print(uid2, HEX); + Serial.print("-"); + Serial.print(uid1, HEX); + Serial.print("-"); + Serial.println(uid0, HEX); + + // MAC Address: typically stored in UID for STM32U series + // Use the lower 6 bytes of the 96-bit UID (commonly used) + uint8_t mac[6] = { + (uint8_t)(uid0 >> 0), + (uint8_t)(uid0 >> 8), + (uint8_t)(uid0 >> 16), + (uint8_t)(uid1 >> 0), + (uint8_t)(uid1 >> 8), + (uint8_t)(uid1 >> 16) + }; + + Serial.print("MAC Address: "); + for (int i = 0; i < 6; i++) { + if (mac[i] < 0x10) Serial.print("0"); + Serial.print(mac[i], HEX); + if (i < 5) Serial.print(":"); + } + Serial.println(); + Serial.printf("Device ID: 0x%x\n", HAL_GetDEVID()); + Serial.printf("Revision ID: 0x%x\n", HAL_GetREVID()); +} + +void loop() { + // Nothing here +} diff --git a/library.properties b/library.properties index 3c18ed3..be51ffb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=STM32duino Examples -version=1.2.2 +version=1.2.7 author=several maintainer=stm32duino sentence=Provides several examples for the Arduino core for STM32 MCUs.