diff --git a/src/common.c b/src/common.c index 57322cefd..4541aa31c 100644 --- a/src/common.c +++ b/src/common.c @@ -1,20 +1,20 @@ #define DEBUG_FLASH 0 #include +#include #include #include #include -#include #include -#include #include -#include #include +#include +#include -#include +#include #include #include -#include +#include #ifdef STLINK_HAVE_SYS_MMAN_H #include @@ -35,7 +35,8 @@ /* stm32f FPEC flash controller interface, pm0063 manual */ // TODO - all of this needs to be abstracted out.... -// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2, August 2012) +// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2, +// August 2012) #define FLASH_REGS_ADDR 0x40022000 #define FLASH_REGS_SIZE 0x28 @@ -48,7 +49,8 @@ #define FLASH_OBR (FLASH_REGS_ADDR + 0x1c) #define FLASH_WRPR (FLASH_REGS_ADDR + 0x20) -// STM32F10x_XL has two flash memory banks with separate registers to control the second bank. +// STM32F10x_XL has two flash memory banks with separate registers to control +// the second bank. #define FLASH_KEYR2 (FLASH_REGS_ADDR + 0x44) #define FLASH_SR2 (FLASH_REGS_ADDR + 0x4c) #define FLASH_CR2 (FLASH_REGS_ADDR + 0x50) @@ -128,113 +130,112 @@ // Mostly the same as STM32G0 chips, but there are a few extra // registers because 'cat 3' devices can have two Flash banks. #define STM32G4_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR) -#define STM32G4_FLASH_PDKEYR (STM32G4_FLASH_REGS_ADDR + 0x04) -#define STM32G4_FLASH_PCROP1SR (STM32G4_FLASH_REGS_ADDR + 0x24) -#define STM32G4_FLASH_PCROP1ER (STM32G4_FLASH_REGS_ADDR + 0x28) -#define STM32G4_FLASH_WRP1AR (STM32G4_FLASH_REGS_ADDR + 0x2C) -#define STM32G4_FLASH_WRP1BR (STM32G4_FLASH_REGS_ADDR + 0x30) -#define STM32G4_FLASH_PCROP2SR (STM32G4_FLASH_REGS_ADDR + 0x44) -#define STM32G4_FLASH_PCROP2ER (STM32G4_FLASH_REGS_ADDR + 0x48) -#define STM32G4_FLASH_WRP2AR (STM32G4_FLASH_REGS_ADDR + 0x4C) -#define STM32G4_FLASH_WRP2BR (STM32G4_FLASH_REGS_ADDR + 0x50) -#define STM32G4_FLASH_SEC1R (STM32G4_FLASH_REGS_ADDR + 0x70) -#define STM32G4_FLASH_SEC2R (STM32G4_FLASH_REGS_ADDR + 0x74) +#define STM32G4_FLASH_PDKEYR (STM32G4_FLASH_REGS_ADDR + 0x04) +#define STM32G4_FLASH_PCROP1SR (STM32G4_FLASH_REGS_ADDR + 0x24) +#define STM32G4_FLASH_PCROP1ER (STM32G4_FLASH_REGS_ADDR + 0x28) +#define STM32G4_FLASH_WRP1AR (STM32G4_FLASH_REGS_ADDR + 0x2C) +#define STM32G4_FLASH_WRP1BR (STM32G4_FLASH_REGS_ADDR + 0x30) +#define STM32G4_FLASH_PCROP2SR (STM32G4_FLASH_REGS_ADDR + 0x44) +#define STM32G4_FLASH_PCROP2ER (STM32G4_FLASH_REGS_ADDR + 0x48) +#define STM32G4_FLASH_WRP2AR (STM32G4_FLASH_REGS_ADDR + 0x4C) +#define STM32G4_FLASH_WRP2BR (STM32G4_FLASH_REGS_ADDR + 0x50) +#define STM32G4_FLASH_SEC1R (STM32G4_FLASH_REGS_ADDR + 0x70) +#define STM32G4_FLASH_SEC2R (STM32G4_FLASH_REGS_ADDR + 0x74) // G0/G4 FLASH control register -#define STM32Gx_FLASH_CR_PG (0) /* Program */ -#define STM32Gx_FLASH_CR_PER (1) /* Page erase */ -#define STM32Gx_FLASH_CR_MER1 (2) /* Mass erase */ -#define STM32Gx_FLASH_CR_PNB (3) /* Page number */ -#define STM32G0_FLASH_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */ -#define STM32G4_FLASH_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */ -#define STM32Gx_FLASH_CR_MER2 (15) /* Mass erase (2nd bank)*/ -#define STM32Gx_FLASH_CR_STRT (16) /* Start */ -#define STM32Gx_FLASH_CR_OPTSTRT (17) /* Start of modification of option bytes */ -#define STM32Gx_FLASH_CR_FSTPG (18) /* Fast programming */ -#define STM32Gx_FLASH_CR_EOPIE (24) /* End of operation interrupt enable */ -#define STM32Gx_FLASH_CR_ERRIE (25) /* Error interrupt enable */ -#define STM32Gx_FLASH_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ -#define STM32Gx_FLASH_CR_OPTLOCK (30) /* Options Lock */ -#define STM32Gx_FLASH_CR_LOCK (31) /* FLASH_CR Lock */ +#define STM32Gx_FLASH_CR_PG (0) /* Program */ +#define STM32Gx_FLASH_CR_PER (1) /* Page erase */ +#define STM32Gx_FLASH_CR_MER1 (2) /* Mass erase */ +#define STM32Gx_FLASH_CR_PNB (3) /* Page number */ +#define STM32G0_FLASH_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */ +#define STM32G4_FLASH_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */ +#define STM32Gx_FLASH_CR_MER2 (15) /* Mass erase (2nd bank)*/ +#define STM32Gx_FLASH_CR_STRT (16) /* Start */ +#define STM32Gx_FLASH_CR_OPTSTRT \ + (17) /* Start of modification of option bytes */ +#define STM32Gx_FLASH_CR_FSTPG (18) /* Fast programming */ +#define STM32Gx_FLASH_CR_EOPIE (24) /* End of operation interrupt enable */ +#define STM32Gx_FLASH_CR_ERRIE (25) /* Error interrupt enable */ +#define STM32Gx_FLASH_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ +#define STM32Gx_FLASH_CR_OPTLOCK (30) /* Options Lock */ +#define STM32Gx_FLASH_CR_LOCK (31) /* FLASH_CR Lock */ // G0/G4 FLASH status register #define STM32Gx_FLASH_SR_ERROR_MASK (0x3fa) -#define STM32Gx_FLASH_SR_PROGERR (3) -#define STM32Gx_FLASH_SR_WRPERR (4) -#define STM32Gx_FLASH_SR_PGAERR (5) -#define STM32Gx_FLASH_SR_BSY (16) /* FLASH_SR Busy */ -#define STM32Gx_FLASH_SR_EOP (0) /* FLASH_EOP End of Operation */ +#define STM32Gx_FLASH_SR_PROGERR (3) +#define STM32Gx_FLASH_SR_WRPERR (4) +#define STM32Gx_FLASH_SR_PGAERR (5) +#define STM32Gx_FLASH_SR_BSY (16) /* FLASH_SR Busy */ +#define STM32Gx_FLASH_SR_EOP (0) /* FLASH_EOP End of Operation */ // G4 FLASH option register -#define STM32G4_FLASH_OPTR_DBANK (22) /* FLASH_OPTR Dual Bank Mode */ +#define STM32G4_FLASH_OPTR_DBANK (22) /* FLASH_OPTR Dual Bank Mode */ // WB (RM0434) #define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000) -#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00) -#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08) -#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C) -#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10) -#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14) -#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18) -#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20) +#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00) +#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08) +#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C) +#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10) +#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14) +#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18) +#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20) #define STM32WB_FLASH_PCROP1ASR (STM32WB_FLASH_REGS_ADDR + 0x24) #define STM32WB_FLASH_PCROP1AER (STM32WB_FLASH_REGS_ADDR + 0x28) -#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C) -#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30) +#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C) +#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30) #define STM32WB_FLASH_PCROP1BSR (STM32WB_FLASH_REGS_ADDR + 0x34) #define STM32WB_FLASH_PCROP1BER (STM32WB_FLASH_REGS_ADDR + 0x38) -#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C) -#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C) -#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60) -#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64) -#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80) -#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84) +#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C) +#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C) +#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60) +#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64) +#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80) +#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84) // WB Flash control register. -#define STM32WB_FLASH_CR_STRT (16) /* Start */ -#define STM32WB_FLASH_CR_OPTLOCK (30) /* Option Lock */ -#define STM32WB_FLASH_CR_LOCK (31) /* Lock */ +#define STM32WB_FLASH_CR_STRT (16) /* Start */ +#define STM32WB_FLASH_CR_OPTLOCK (30) /* Option Lock */ +#define STM32WB_FLASH_CR_LOCK (31) /* Lock */ // WB Flash status register. #define STM32WB_FLASH_SR_ERROR_MASK (0x3f8) /* SR [9:3] */ -#define STM32WB_FLASH_SR_PROGERR (3) /* Programming alignment error */ -#define STM32WB_FLASH_SR_WRPERR (4) /* Write protection error */ -#define STM32WB_FLASH_SR_PGAERR (5) /* Programming error */ -#define STM32WB_FLASH_SR_BSY (16) /* Busy */ +#define STM32WB_FLASH_SR_PROGERR (3) /* Programming alignment error */ +#define STM32WB_FLASH_SR_WRPERR (4) /* Write protection error */ +#define STM32WB_FLASH_SR_PGAERR (5) /* Programming error */ +#define STM32WB_FLASH_SR_BSY (16) /* Busy */ // 32L4 register base is at FLASH_REGS_ADDR (0x40022000) -#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08) -#define STM32L4_FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x0C) -#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10) -#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14) -#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20) +#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08) +#define STM32L4_FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x0C) +#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10) +#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14) +#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20) #define STM32L4_FLASH_SR_ERROR_MASK 0x3f8 /* SR [9:3] */ -#define STM32L4_FLASH_SR_PROGERR 3 -#define STM32L4_FLASH_SR_WRPERR 4 -#define STM32L4_FLASH_SR_PGAERR 5 -#define STM32L4_FLASH_SR_BSY 16 - -#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */ -#define STM32L4_FLASH_CR_OPTLOCK 30 /* Lock option bytes */ -#define STM32L4_FLASH_CR_PG 0 /* Program */ -#define STM32L4_FLASH_CR_PER 1 /* Page erase */ -#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */ -#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */ -#define STM32L4_FLASH_CR_STRT 16 /* Start command */ -#define STM32L4_FLASH_CR_OPTSTRT 17 /* Start writing option bytes */ -#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */ -#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */ +#define STM32L4_FLASH_SR_PROGERR 3 +#define STM32L4_FLASH_SR_WRPERR 4 +#define STM32L4_FLASH_SR_PGAERR 5 +#define STM32L4_FLASH_SR_BSY 16 + +#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */ +#define STM32L4_FLASH_CR_OPTLOCK 30 /* Lock option bytes */ +#define STM32L4_FLASH_CR_PG 0 /* Program */ +#define STM32L4_FLASH_CR_PER 1 /* Page erase */ +#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */ +#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */ +#define STM32L4_FLASH_CR_STRT 16 /* Start command */ +#define STM32L4_FLASH_CR_OPTSTRT 17 /* Start writing option bytes */ +#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */ +#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */ #define STM32L4_FLASH_CR_OBL_LAUNCH 27 /* Option bytes reload */ // Bits requesting flash operations (useful when we want to clear them) -#define STM32L4_FLASH_CR_OPBITS \ - (uint32_t)((1lu << STM32L4_FLASH_CR_PG) | \ - (1lu << STM32L4_FLASH_CR_PER) | \ - (1lu << STM32L4_FLASH_CR_MER1) | \ - (1lu << STM32L4_FLASH_CR_MER1)) +#define STM32L4_FLASH_CR_OPBITS \ + (uint32_t)((1lu << STM32L4_FLASH_CR_PG) | (1lu << STM32L4_FLASH_CR_PER) | \ + (1lu << STM32L4_FLASH_CR_MER1) | (1lu << STM32L4_FLASH_CR_MER1)) // Page is fully specified by BKER and PNB #define STM32L4_FLASH_CR_PAGEMASK (uint32_t)(0x1fflu << STM32L4_FLASH_CR_PNB) -#define STM32L4_FLASH_OPTR_DUALBANK 21 +#define STM32L4_FLASH_OPTR_DUALBANK 21 // STM32L0x flash register base and offsets RM0090 - DM00031020.pdf #define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000) @@ -245,21 +246,21 @@ #define STM32L0_FLASH_OBL_LAUNCH (18) #define STM32L0_FLASH_SR_ERROR_MASK 0x00013F00 -#define STM32L0_FLASH_SR_WRPERR 8 -#define STM32L0_FLASH_SR_PGAERR 9 +#define STM32L0_FLASH_SR_WRPERR 8 +#define STM32L0_FLASH_SR_PGAERR 9 #define STM32L0_FLASH_SR_NOTZEROERR 16 -#define FLASH_ACR_OFF ((uint32_t) 0x00) -#define FLASH_PECR_OFF ((uint32_t) 0x04) -#define FLASH_PDKEYR_OFF ((uint32_t) 0x08) -#define FLASH_PEKEYR_OFF ((uint32_t) 0x0c) -#define FLASH_PRGKEYR_OFF ((uint32_t) 0x10) -#define FLASH_OPTKEYR_OFF ((uint32_t) 0x14) -#define FLASH_SR_OFF ((uint32_t) 0x18) -#define FLASH_OBR_OFF ((uint32_t) 0x1c) -#define FLASH_WRPR_OFF ((uint32_t) 0x20) - -//STM32F7 +#define FLASH_ACR_OFF ((uint32_t)0x00) +#define FLASH_PECR_OFF ((uint32_t)0x04) +#define FLASH_PDKEYR_OFF ((uint32_t)0x08) +#define FLASH_PEKEYR_OFF ((uint32_t)0x0c) +#define FLASH_PRGKEYR_OFF ((uint32_t)0x10) +#define FLASH_OPTKEYR_OFF ((uint32_t)0x14) +#define FLASH_SR_OFF ((uint32_t)0x18) +#define FLASH_OBR_OFF ((uint32_t)0x1c) +#define FLASH_WRPR_OFF ((uint32_t)0x20) + +// STM32F7 #define FLASH_F7_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_F7_KEYR (FLASH_F7_REGS_ADDR + 0x04) #define FLASH_F7_OPT_KEYR (FLASH_F7_REGS_ADDR + 0x08) @@ -279,14 +280,17 @@ #define FLASH_F7_SR_PGP_ERR 6 /* Programming parallelism error */ #define FLASH_F7_SR_PGA_ERR 5 /* Programming alignment error */ #define FLASH_F7_SR_WRP_ERR 4 /* Write protection error */ -#define FLASH_F7_SR_OP_ERR 1 /* Operation error */ -#define FLASH_F7_SR_EOP 0 /* End of operation */ +#define FLASH_F7_SR_OP_ERR 1 /* Operation error */ +#define FLASH_F7_SR_EOP 0 /* End of operation */ #define FLASH_F7_OPTCR1_BOOT_ADD0 0 #define FLASH_F7_OPTCR1_BOOT_ADD1 16 -#define FLASH_F7_SR_ERROR_MASK ((1 << FLASH_F7_SR_ERS_ERR) | (1 << FLASH_F7_SR_PGP_ERR) | (1 << FLASH_F7_SR_PGA_ERR) | (1 << FLASH_F7_SR_WRP_ERR) | (1 << FLASH_F7_SR_OP_ERR)) +#define FLASH_F7_SR_ERROR_MASK \ + ((1 << FLASH_F7_SR_ERS_ERR) | (1 << FLASH_F7_SR_PGP_ERR) | \ + (1 << FLASH_F7_SR_PGA_ERR) | (1 << FLASH_F7_SR_WRP_ERR) | \ + (1 << FLASH_F7_SR_OP_ERR)) -//STM32F4 +// STM32F4 #define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04) #define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08) @@ -301,9 +305,9 @@ #define FLASH_F4_CR_SNB 3 #define FLASH_F4_CR_SNB_MASK 0xf8 #define FLASH_F4_SR_ERROR_MASK 0x000000F0 -#define FLASH_F4_SR_PGAERR 5 -#define FLASH_F4_SR_WRPERR 4 -#define FLASH_F4_SR_BSY 16 +#define FLASH_F4_SR_PGAERR 5 +#define FLASH_F4_SR_WRPERR 4 +#define FLASH_F4_SR_BSY 16 // STM32F2 #define FLASH_F2_REGS_ADDR ((uint32_t)0x40023c00) @@ -327,15 +331,17 @@ #define FLASH_H7_CR_SER 2 #define FLASH_H7_CR_BER 3 #define FLASH_H7_CR_PSIZE 4 -#define FLASH_H7_CR_START(chipid) (chipid==STLINK_CHIPID_STM32_H7AX?5:7) +#define FLASH_H7_CR_START(chipid) (chipid == STLINK_CHIPID_STM32_H7AX ? 5 : 7) #define FLASH_H7_CR_SNB 8 #define FLASH_H7_CR_SNB_MASK 0x700 -#define FLASH_H7_SR_QW 2 +#define FLASH_H7_SR_QW 2 #define FLASH_H7_SR_WRPERR 17 #define FLASH_H7_SR_PGSERR 18 #define FLASH_H7_SR_STRBERR 19 -#define FLASH_H7_SR_ERROR_MASK ((1 << FLASH_H7_SR_PGSERR) | (1 << FLASH_H7_SR_STRBERR) | (1 << FLASH_H7_SR_WRPERR)) +#define FLASH_H7_SR_ERROR_MASK \ + ((1 << FLASH_H7_SR_PGSERR) | (1 << FLASH_H7_SR_STRBERR) | \ + (1 << FLASH_H7_SR_WRPERR)) #define FLASH_H7_OPTCR_OPTLOCK 0 #define FLASH_H7_OPTCR_OPTSTART 1 @@ -362,1189 +368,1188 @@ #define FLASH_H7_OPTSR_CUR (FLASH_H7_REGS_ADDR + 0x1c) #define FLASH_H7_OPTCCR (FLASH_H7_REGS_ADDR + 0x24) -#define STM32F0_DBGMCU_CR 0xE0042004 -#define STM32F0_DBGMCU_CR_IWDG_STOP 8 -#define STM32F0_DBGMCU_CR_WWDG_STOP 9 +#define STM32F0_DBGMCU_CR 0xE0042004 +#define STM32F0_DBGMCU_CR_IWDG_STOP 8 +#define STM32F0_DBGMCU_CR_WWDG_STOP 9 -#define STM32F4_DBGMCU_APB1FZR1 0xE0042008 +#define STM32F4_DBGMCU_APB1FZR1 0xE0042008 #define STM32F4_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32F4_DBGMCU_APB1FZR1_IWDG_STOP 12 -#define STM32L0_DBGMCU_APB1_FZ 0x40015808 -#define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11 -#define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12 +#define STM32L0_DBGMCU_APB1_FZ 0x40015808 +#define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11 +#define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12 -#define STM32H7_DBGMCU_APB1HFZ 0x5C001054 -#define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18 +#define STM32H7_DBGMCU_APB1HFZ 0x5C001054 +#define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18 -#define STM32WB_DBGMCU_APB1FZR1 0xE004203C +#define STM32WB_DBGMCU_APB1FZR1 0xE004203C #define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12 -#define STM32F1_RCC_AHBENR 0x40021014 -#define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN +#define STM32F1_RCC_AHBENR 0x40021014 +#define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN -#define STM32F4_RCC_AHB1ENR 0x40023830 -#define STM32F4_RCC_DMAEN 0x00600000 // DMA2EN | DMA1EN +#define STM32F4_RCC_AHB1ENR 0x40023830 +#define STM32F4_RCC_DMAEN 0x00600000 // DMA2EN | DMA1EN -#define STM32G0_RCC_AHBENR 0x40021038 -#define STM32G0_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN +#define STM32G0_RCC_AHBENR 0x40021038 +#define STM32G0_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN -#define STM32G4_RCC_AHB1ENR 0x40021048 -#define STM32G4_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN +#define STM32G4_RCC_AHB1ENR 0x40021048 +#define STM32G4_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN -#define STM32L0_RCC_AHBENR 0x40021030 -#define STM32L0_RCC_DMAEN 0x00000001 // DMAEN +#define STM32L0_RCC_AHBENR 0x40021030 +#define STM32L0_RCC_DMAEN 0x00000001 // DMAEN -#define STM32H7_RCC_AHB1ENR 0x58024538 -#define STM32H7_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN +#define STM32H7_RCC_AHB1ENR 0x58024538 +#define STM32H7_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN -#define STM32WB_RCC_AHB1ENR 0x58000048 -#define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN +#define STM32WB_RCC_AHB1ENR 0x58000048 +#define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define L1_WRITE_BLOCK_SIZE 0x80 #define L0_WRITE_BLOCK_SIZE 0x40 - // Endianness // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html // These functions encode and decode little endian uint16 and uint32 values. -void write_uint32(unsigned char* buf, uint32_t ui) { - buf[0] = ui; - buf[1] = ui >> 8; - buf[2] = ui >> 16; - buf[3] = ui >> 24; +void write_uint32(unsigned char *buf, uint32_t ui) { + buf[0] = ui; + buf[1] = ui >> 8; + buf[2] = ui >> 16; + buf[3] = ui >> 24; } -void write_uint16(unsigned char* buf, uint16_t ui) { - buf[0] = ui ; - buf[1] = ui >> 8; +void write_uint16(unsigned char *buf, uint16_t ui) { + buf[0] = ui; + buf[1] = ui >> 8; } uint32_t read_uint32(const unsigned char *c, const int pt) { - return ((uint32_t)c[pt]) | ((uint32_t)c[pt+1] << 8) | ((uint32_t)c[pt+2] << 16) | ((uint32_t)c[pt+3] << 24) ; + return ((uint32_t)c[pt]) | ((uint32_t)c[pt + 1] << 8) | + ((uint32_t)c[pt + 2] << 16) | ((uint32_t)c[pt + 3] << 24); } uint16_t read_uint16(const unsigned char *c, const int pt) { - return ((uint16_t)c[pt]) | ((uint16_t)c[pt+1] << 8); + return ((uint16_t)c[pt]) | ((uint16_t)c[pt + 1] << 8); } +static uint32_t get_stm32l0_flash_base(stlink_t *sl) { + switch (sl->chip_id) { + case STLINK_CHIPID_STM32_L0: + case STLINK_CHIPID_STM32_L0_CAT5: + case STLINK_CHIPID_STM32_L0_CAT2: + case STLINK_CHIPID_STM32_L011: + return (STM32L0_FLASH_REGS_ADDR); -static uint32_t get_stm32l0_flash_base(stlink_t *sl) -{ - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_L0: - case STLINK_CHIPID_STM32_L0_CAT5: - case STLINK_CHIPID_STM32_L0_CAT2: - case STLINK_CHIPID_STM32_L011: - return(STM32L0_FLASH_REGS_ADDR); - - case STLINK_CHIPID_STM32_L1_CAT2: - case STLINK_CHIPID_STM32_L1_MEDIUM: - case STLINK_CHIPID_STM32_L1_MEDIUM_PLUS: - case STLINK_CHIPID_STM32_L1_HIGH: - return(STM32L1_FLASH_REGS_ADDR); + case STLINK_CHIPID_STM32_L1_CAT2: + case STLINK_CHIPID_STM32_L1_MEDIUM: + case STLINK_CHIPID_STM32_L1_MEDIUM_PLUS: + case STLINK_CHIPID_STM32_L1_HIGH: + return (STM32L1_FLASH_REGS_ADDR); - default: - WLOG("Flash base use default L0 address"); - return(STM32L0_FLASH_REGS_ADDR); - } + default: + WLOG("Flash base use default L0 address"); + return (STM32L0_FLASH_REGS_ADDR); + } } static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) { - uint32_t rdp; - stlink_read_debug32(sl, FLASH_WRPR, &rdp); - return(rdp & 0xff); + uint32_t rdp; + stlink_read_debug32(sl, FLASH_WRPR, &rdp); + return (rdp & 0xff); } static inline uint32_t read_flash_cr(stlink_t *sl, unsigned bank) { - uint32_t reg, res; - - if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - reg = FLASH_F4_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - reg = FLASH_F7_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - reg = STM32L4_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - reg = STM32WB_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - reg = (bank == BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - } else { - reg = (bank == BANK_1)?FLASH_CR:FLASH_CR2; - } - - stlink_read_debug32(sl, reg, &res); + uint32_t reg, res; + + if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + reg = FLASH_F4_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + reg = FLASH_F7_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + reg = STM32L4_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + reg = STM32WB_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + } else { + reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; + } + + stlink_read_debug32(sl, reg, &res); #if DEBUG_FLASH - fprintf(stdout, "CR:0x%x\n", res); + fprintf(stdout, "CR:0x%x\n", res); #endif - return(res); + return (res); } static inline unsigned int is_flash_locked(stlink_t *sl) { - /* return non zero for true */ - uint32_t cr_lock_shift; - uint32_t cr_reg; - uint32_t n; - - if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { - cr_reg = FLASH_CR; - cr_lock_shift = FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - cr_lock_shift = FLASH_F4_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - cr_lock_shift = FLASH_F7_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - cr_lock_shift = STM32L0_FLASH_PELOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - cr_lock_shift = STM32L4_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_lock_shift = STM32Gx_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - cr_lock_shift = STM32WB_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = FLASH_H7_CR1; - cr_lock_shift = FLASH_H7_CR_LOCK; - } else { - ELOG("unsupported flash method, abort\n"); - return(-1); - } - - stlink_read_debug32(sl, cr_reg, &n); - return(n & (1u << cr_lock_shift)); + /* return non zero for true */ + uint32_t cr_lock_shift; + uint32_t cr_reg; + uint32_t n; + + if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { + cr_reg = FLASH_CR; + cr_lock_shift = FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + cr_lock_shift = FLASH_F4_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + cr_lock_shift = FLASH_F7_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + cr_lock_shift = STM32L0_FLASH_PELOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = FLASH_H7_CR1; + cr_lock_shift = FLASH_H7_CR_LOCK; + } else { + ELOG("unsupported flash method, abort\n"); + return (-1); + } + + stlink_read_debug32(sl, cr_reg, &n); + return (n & (1u << cr_lock_shift)); } static void unlock_flash(stlink_t *sl) { - uint32_t key_reg, key2_reg = 0; - uint32_t flash_key1 = FLASH_KEY1; - uint32_t flash_key2 = FLASH_KEY2; - /* The unlock sequence consists of 2 write cycles where 2 key values are written - * to the FLASH_KEYR register. - * An invalid sequence results in a definitive lock of the FPEC block until next reset. - */ - - if (sl->flash_type == STLINK_FLASH_TYPE_F0) { - key_reg = FLASH_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { - key_reg = FLASH_KEYR; - key2_reg = FLASH_KEYR2; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - key_reg = FLASH_F4_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - key_reg = FLASH_F7_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF; - flash_key1 = FLASH_L0_PEKEY1; - flash_key2 = FLASH_L0_PEKEY2; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - key_reg = STM32L4_FLASH_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - key_reg = STM32Gx_FLASH_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - key_reg = STM32WB_FLASH_KEYR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - key_reg = FLASH_H7_KEYR1; - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - key2_reg = FLASH_H7_KEYR2; - } - } else { - ELOG("unsupported flash method, abort\n"); - return; - } + uint32_t key_reg, key2_reg = 0; + uint32_t flash_key1 = FLASH_KEY1; + uint32_t flash_key2 = FLASH_KEY2; + /* The unlock sequence consists of 2 write cycles where 2 key values are + * written to the FLASH_KEYR register. An invalid sequence results in a + * definitive lock of the FPEC block until next reset. + */ + + if (sl->flash_type == STLINK_FLASH_TYPE_F0) { + key_reg = FLASH_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { + key_reg = FLASH_KEYR; + key2_reg = FLASH_KEYR2; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + key_reg = FLASH_F4_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + key_reg = FLASH_F7_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF; + flash_key1 = FLASH_L0_PEKEY1; + flash_key2 = FLASH_L0_PEKEY2; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + key_reg = STM32L4_FLASH_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + key_reg = STM32Gx_FLASH_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + key_reg = STM32WB_FLASH_KEYR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + key_reg = FLASH_H7_KEYR1; + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + key2_reg = FLASH_H7_KEYR2; + } + } else { + ELOG("unsupported flash method, abort\n"); + return; + } - stlink_write_debug32(sl, key_reg, flash_key1); - stlink_write_debug32(sl, key_reg, flash_key2); + stlink_write_debug32(sl, key_reg, flash_key1); + stlink_write_debug32(sl, key_reg, flash_key2); - if (key2_reg) { - stlink_write_debug32(sl, key2_reg, flash_key1); - stlink_write_debug32(sl, key2_reg, flash_key2); - } + if (key2_reg) { + stlink_write_debug32(sl, key2_reg, flash_key1); + stlink_write_debug32(sl, key2_reg, flash_key2); + } } /* unlock flash if already locked */ static int unlock_flash_if(stlink_t *sl) { - if (is_flash_locked(sl)) { - unlock_flash(sl); + if (is_flash_locked(sl)) { + unlock_flash(sl); - if (is_flash_locked(sl)) { - WLOG("Failed to unlock flash!\n"); - return(-1); - } + if (is_flash_locked(sl)) { + WLOG("Failed to unlock flash!\n"); + return (-1); } + } - DLOG("Successfully unlocked flash\n"); - return(0); + DLOG("Successfully unlocked flash\n"); + return (0); } static void lock_flash(stlink_t *sl) { - uint32_t cr_lock_shift, cr_reg, n, cr2_reg = 0; - uint32_t cr_mask = 0xffffffffu; - - if (sl->flash_type == STLINK_FLASH_TYPE_F0) { - cr_reg = FLASH_CR; - cr_lock_shift = FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { - cr_reg = FLASH_CR; - cr2_reg = FLASH_CR2; - cr_lock_shift = FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - cr_lock_shift = FLASH_F4_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - cr_lock_shift = FLASH_F7_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - cr_lock_shift = STM32L0_FLASH_PELOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - cr_lock_shift = STM32L4_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_lock_shift = STM32Gx_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - cr_lock_shift = STM32WB_FLASH_CR_LOCK; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = FLASH_H7_CR1; - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - cr2_reg = FLASH_H7_CR2; - } - cr_lock_shift = FLASH_H7_CR_LOCK; - cr_mask = ~(1u << FLASH_H7_CR_SER); - } else { - ELOG("unsupported flash method, abort\n"); - return; - } + uint32_t cr_lock_shift, cr_reg, n, cr2_reg = 0; + uint32_t cr_mask = 0xffffffffu; + + if (sl->flash_type == STLINK_FLASH_TYPE_F0) { + cr_reg = FLASH_CR; + cr_lock_shift = FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { + cr_reg = FLASH_CR; + cr2_reg = FLASH_CR2; + cr_lock_shift = FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + cr_lock_shift = FLASH_F4_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + cr_lock_shift = FLASH_F7_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + cr_lock_shift = STM32L0_FLASH_PELOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = FLASH_H7_CR1; + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + cr2_reg = FLASH_H7_CR2; + } + cr_lock_shift = FLASH_H7_CR_LOCK; + cr_mask = ~(1u << FLASH_H7_CR_SER); + } else { + ELOG("unsupported flash method, abort\n"); + return; + } - stlink_read_debug32(sl, cr_reg, &n); - n &= cr_mask; - n |= (1u << cr_lock_shift); - stlink_write_debug32(sl, cr_reg, n); + stlink_read_debug32(sl, cr_reg, &n); + n &= cr_mask; + n |= (1u << cr_lock_shift); + stlink_write_debug32(sl, cr_reg, n); - if (cr2_reg) { - n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift); - stlink_write_debug32(sl, cr2_reg, n); - } + if (cr2_reg) { + n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift); + stlink_write_debug32(sl, cr2_reg, n); + } } static bool is_flash_option_locked(stlink_t *sl) { - uint32_t optlock_shift, optcr_reg; - int active_bit_level = 1; - uint32_t n; - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - optcr_reg = FLASH_CR; - optlock_shift = FLASH_CR_OPTWRE; - active_bit_level = 0; /* bit is "option write enable", not lock */ - break; - case STLINK_FLASH_TYPE_F4: - optcr_reg = FLASH_F4_OPTCR; - optlock_shift = FLASH_F4_OPTCR_LOCK; - break; - case STLINK_FLASH_TYPE_F7: - optcr_reg = FLASH_F7_OPTCR; - optlock_shift = FLASH_F7_OPTCR_LOCK; - break; - case STLINK_FLASH_TYPE_L0: - optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - optlock_shift = STM32L0_FLASH_OPTLOCK; - break; - case STLINK_FLASH_TYPE_L4: - optcr_reg = STM32L4_FLASH_CR; - optlock_shift = STM32L4_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - optcr_reg = STM32Gx_FLASH_CR; - optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_WB: - optcr_reg = STM32WB_FLASH_CR; - optlock_shift = STM32WB_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_H7: - optcr_reg = FLASH_H7_OPTCR; - optlock_shift = FLASH_H7_OPTCR_OPTLOCK; - break; - default: - ELOG("unsupported flash method, abort\n"); - return -1; - } - - stlink_read_debug32(sl, optcr_reg, &n); - - if (active_bit_level == 0) { - return(!(n & (1u << optlock_shift))); - } - - return(n & (1u << optlock_shift)); - + uint32_t optlock_shift, optcr_reg; + int active_bit_level = 1; + uint32_t n; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + optcr_reg = FLASH_CR; + optlock_shift = FLASH_CR_OPTWRE; + active_bit_level = 0; /* bit is "option write enable", not lock */ + break; + case STLINK_FLASH_TYPE_F4: + optcr_reg = FLASH_F4_OPTCR; + optlock_shift = FLASH_F4_OPTCR_LOCK; + break; + case STLINK_FLASH_TYPE_F7: + optcr_reg = FLASH_F7_OPTCR; + optlock_shift = FLASH_F7_OPTCR_LOCK; + break; + case STLINK_FLASH_TYPE_L0: + optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + optlock_shift = STM32L0_FLASH_OPTLOCK; + break; + case STLINK_FLASH_TYPE_L4: + optcr_reg = STM32L4_FLASH_CR; + optlock_shift = STM32L4_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + optcr_reg = STM32Gx_FLASH_CR; + optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_WB: + optcr_reg = STM32WB_FLASH_CR; + optlock_shift = STM32WB_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_H7: + optcr_reg = FLASH_H7_OPTCR; + optlock_shift = FLASH_H7_OPTCR_OPTLOCK; + break; + default: + ELOG("unsupported flash method, abort\n"); + return -1; + } + + stlink_read_debug32(sl, optcr_reg, &n); + + if (active_bit_level == 0) { + return (!(n & (1u << optlock_shift))); + } + + return (n & (1u << optlock_shift)); } static int lock_flash_option(stlink_t *sl) { - uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0; - int active_bit_level = 1; - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - optcr_reg = FLASH_CR; - optlock_shift = FLASH_CR_OPTWRE; - active_bit_level = 0; - break; - case STLINK_FLASH_TYPE_F4: - optcr_reg = FLASH_F4_OPTCR; - optlock_shift = FLASH_F4_OPTCR_LOCK; - break; - case STLINK_FLASH_TYPE_F7: - optcr_reg = FLASH_F7_OPTCR; - optlock_shift = FLASH_F7_OPTCR_LOCK; - break; - case STLINK_FLASH_TYPE_L0: - optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - optlock_shift = STM32L0_FLASH_OPTLOCK; - break; - case STLINK_FLASH_TYPE_L4: - optcr_reg = STM32L4_FLASH_CR; - optlock_shift = STM32L4_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - optcr_reg = STM32Gx_FLASH_CR; - optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_WB: - optcr_reg = STM32WB_FLASH_CR; - optlock_shift = STM32WB_FLASH_CR_OPTLOCK; - break; - case STLINK_FLASH_TYPE_H7: - optcr_reg = FLASH_H7_OPTCR; - optlock_shift = FLASH_H7_OPTCR_OPTLOCK; - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) - optcr2_reg = FLASH_H7_OPTCR2; - break; - default: - ELOG("unsupported flash method, abort\n"); - return -1; - } - - stlink_read_debug32(sl, optcr_reg, &n); + uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0; + int active_bit_level = 1; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + optcr_reg = FLASH_CR; + optlock_shift = FLASH_CR_OPTWRE; + active_bit_level = 0; + break; + case STLINK_FLASH_TYPE_F4: + optcr_reg = FLASH_F4_OPTCR; + optlock_shift = FLASH_F4_OPTCR_LOCK; + break; + case STLINK_FLASH_TYPE_F7: + optcr_reg = FLASH_F7_OPTCR; + optlock_shift = FLASH_F7_OPTCR_LOCK; + break; + case STLINK_FLASH_TYPE_L0: + optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + optlock_shift = STM32L0_FLASH_OPTLOCK; + break; + case STLINK_FLASH_TYPE_L4: + optcr_reg = STM32L4_FLASH_CR; + optlock_shift = STM32L4_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + optcr_reg = STM32Gx_FLASH_CR; + optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_WB: + optcr_reg = STM32WB_FLASH_CR; + optlock_shift = STM32WB_FLASH_CR_OPTLOCK; + break; + case STLINK_FLASH_TYPE_H7: + optcr_reg = FLASH_H7_OPTCR; + optlock_shift = FLASH_H7_OPTCR_OPTLOCK; + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) + optcr2_reg = FLASH_H7_OPTCR2; + break; + default: + ELOG("unsupported flash method, abort\n"); + return -1; + } + + stlink_read_debug32(sl, optcr_reg, &n); + + if (active_bit_level == 0) { + n &= ~(1u << optlock_shift); + } else { + n |= (1u << optlock_shift); + } + + stlink_write_debug32(sl, optcr_reg, n); + + if (optcr2_reg) { + stlink_read_debug32(sl, optcr2_reg, &n); if (active_bit_level == 0) { - n &= ~(1u << optlock_shift); + n &= ~(1u << optlock_shift); } else { - n |= (1u << optlock_shift); + n |= (1u << optlock_shift); } - stlink_write_debug32(sl, optcr_reg, n); + stlink_write_debug32(sl, optcr2_reg, n); + } - if (optcr2_reg) { - stlink_read_debug32(sl, optcr2_reg, &n); - - if (active_bit_level == 0) { - n &= ~(1u << optlock_shift); - } else { - n |= (1u << optlock_shift); - } - - stlink_write_debug32(sl, optcr2_reg, n); - } - - return(0); + return (0); } static int unlock_flash_option(stlink_t *sl) { - uint32_t optkey_reg, optkey2_reg = 0; - uint32_t optkey1 = FLASH_OPTKEY1; - uint32_t optkey2 = FLASH_OPTKEY2; - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - optkey_reg = FLASH_OPTKEYR; - optkey1 = FLASH_F0_OPTKEY1; - optkey2 = FLASH_F0_OPTKEY2; - break; - case STLINK_FLASH_TYPE_F4: - optkey_reg = FLASH_F4_OPT_KEYR; - break; - case STLINK_FLASH_TYPE_F7: - optkey_reg = FLASH_F7_OPT_KEYR; - break; - case STLINK_FLASH_TYPE_L0: - optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF; - optkey1 = FLASH_L0_OPTKEY1; - optkey2 = FLASH_L0_OPTKEY2; - break; - case STLINK_FLASH_TYPE_L4: - optkey_reg = STM32L4_FLASH_OPTKEYR; - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - optkey_reg = STM32Gx_FLASH_OPTKEYR; - break; - case STLINK_FLASH_TYPE_WB: - optkey_reg = STM32WB_FLASH_OPT_KEYR; - break; - case STLINK_FLASH_TYPE_H7: - optkey_reg = FLASH_H7_OPT_KEYR; - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) - optkey2_reg = FLASH_H7_OPT_KEYR2; - break; - default: - ELOG("unsupported flash method, abort\n"); - return(-1); - } - - stlink_write_debug32(sl, optkey_reg, optkey1); - stlink_write_debug32(sl, optkey_reg, optkey2); - - if (optkey2_reg) { - stlink_write_debug32(sl, optkey2_reg, optkey1); - stlink_write_debug32(sl, optkey2_reg, optkey2); - } - - return(0); + uint32_t optkey_reg, optkey2_reg = 0; + uint32_t optkey1 = FLASH_OPTKEY1; + uint32_t optkey2 = FLASH_OPTKEY2; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + optkey_reg = FLASH_OPTKEYR; + optkey1 = FLASH_F0_OPTKEY1; + optkey2 = FLASH_F0_OPTKEY2; + break; + case STLINK_FLASH_TYPE_F4: + optkey_reg = FLASH_F4_OPT_KEYR; + break; + case STLINK_FLASH_TYPE_F7: + optkey_reg = FLASH_F7_OPT_KEYR; + break; + case STLINK_FLASH_TYPE_L0: + optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF; + optkey1 = FLASH_L0_OPTKEY1; + optkey2 = FLASH_L0_OPTKEY2; + break; + case STLINK_FLASH_TYPE_L4: + optkey_reg = STM32L4_FLASH_OPTKEYR; + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + optkey_reg = STM32Gx_FLASH_OPTKEYR; + break; + case STLINK_FLASH_TYPE_WB: + optkey_reg = STM32WB_FLASH_OPT_KEYR; + break; + case STLINK_FLASH_TYPE_H7: + optkey_reg = FLASH_H7_OPT_KEYR; + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) + optkey2_reg = FLASH_H7_OPT_KEYR2; + break; + default: + ELOG("unsupported flash method, abort\n"); + return (-1); + } + + stlink_write_debug32(sl, optkey_reg, optkey1); + stlink_write_debug32(sl, optkey_reg, optkey2); + + if (optkey2_reg) { + stlink_write_debug32(sl, optkey2_reg, optkey1); + stlink_write_debug32(sl, optkey2_reg, optkey2); + } + + return (0); } static int unlock_flash_option_if(stlink_t *sl) { - if (is_flash_option_locked(sl)) { - if (unlock_flash_option(sl)) { - ELOG("Could not unlock flash option!\n"); - return(-1); - } + if (is_flash_option_locked(sl)) { + if (unlock_flash_option(sl)) { + ELOG("Could not unlock flash option!\n"); + return (-1); + } - if (is_flash_option_locked(sl)) { - ELOG("Failed to unlock flash option!\n"); - return(-1); - } + if (is_flash_option_locked(sl)) { + ELOG("Failed to unlock flash option!\n"); + return (-1); } + } - DLOG("Successfully unlocked flash option\n"); - return(0); + DLOG("Successfully unlocked flash option\n"); + return (0); } static void set_flash_cr_pg(stlink_t *sl, unsigned bank) { - uint32_t cr_reg, x; - - x = read_flash_cr(sl, bank); - - if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - x |= 1 << FLASH_CR_PG; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - x |= 1 << FLASH_CR_PG; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - x &= ~STM32L4_FLASH_CR_OPBITS; - x |= (1 << STM32L4_FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - x |= (1 << FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - x |= (1 << FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank == BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - x |= (1 << FLASH_H7_CR_PG); - } else { - cr_reg = FLASH_CR; - x = (1 << FLASH_CR_PG); - } - - stlink_write_debug32(sl, cr_reg, x); + uint32_t cr_reg, x; + + x = read_flash_cr(sl, bank); + + if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + x |= 1 << FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + x |= 1 << FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + x &= ~STM32L4_FLASH_CR_OPBITS; + x |= (1 << STM32L4_FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + x |= (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + x |= (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + x |= (1 << FLASH_H7_CR_PG); + } else { + cr_reg = FLASH_CR; + x = (1 << FLASH_CR_PG); + } + + stlink_write_debug32(sl, cr_reg, x); } static void clear_flash_cr_pg(stlink_t *sl, unsigned bank) { - uint32_t cr_reg, n; - uint32_t bit = FLASH_CR_PG; - - if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank == BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - bit = FLASH_H7_CR_PG; - } else { - cr_reg = FLASH_CR; - } - - n = read_flash_cr(sl, bank) & ~(1 << bit); - stlink_write_debug32(sl, cr_reg, n); + uint32_t cr_reg, n; + uint32_t bit = FLASH_CR_PG; + + if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + bit = FLASH_H7_CR_PG; + } else { + cr_reg = FLASH_CR; + } + + n = read_flash_cr(sl, bank) & ~(1 << bit); + stlink_write_debug32(sl, cr_reg, n); } static void set_flash_cr_per(stlink_t *sl, unsigned bank) { - uint32_t cr_reg, val; + uint32_t cr_reg, val; - if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - } else { - cr_reg = (bank==BANK_1)?FLASH_CR:FLASH_CR2; - } + if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + } else { + cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; + } - stlink_read_debug32(sl, cr_reg, &val); - val |= (1 << FLASH_CR_PER); - stlink_write_debug32(sl, cr_reg, val); + stlink_read_debug32(sl, cr_reg, &val); + val |= (1 << FLASH_CR_PER); + stlink_write_debug32(sl, cr_reg, val); } static void clear_flash_cr_per(stlink_t *sl, unsigned bank) { - uint32_t cr_reg; + uint32_t cr_reg; - if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - } else { - cr_reg = (bank==BANK_1)?FLASH_CR:FLASH_CR2; - } + if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + } else { + cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; + } - const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER); - stlink_write_debug32(sl, cr_reg, n); + const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER); + stlink_write_debug32(sl, cr_reg, n); } static void set_flash_cr_mer(stlink_t *sl, bool v, unsigned bank) { - uint32_t val, cr_reg, cr_mer, cr_pg; - - if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - cr_mer = 1 << FLASH_CR_MER; - cr_pg = 1 << FLASH_CR_PG; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - cr_mer = 1 << FLASH_CR_MER; - cr_pg = 1 << FLASH_CR_PG; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2); - cr_pg = (1 << STM32L4_FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_mer = (1 << STM32Gx_FLASH_CR_MER1); - - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - cr_mer |= (1 << STM32Gx_FLASH_CR_MER2); - } - - cr_pg = (1 << FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - cr_mer = (1 << FLASH_CR_MER); - cr_pg = (1 << FLASH_CR_PG); - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank==BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - cr_mer = (1 << FLASH_H7_CR_BER); - cr_pg = (1 << FLASH_H7_CR_PG); - } else { - cr_reg = (bank==BANK_1)?FLASH_CR:FLASH_CR2; - cr_mer = (1 << FLASH_CR_MER); - cr_pg = (1 << FLASH_CR_PG); - } - - stlink_read_debug32(sl, cr_reg, &val); - - if (val & cr_pg) { - // STM32F030 will drop MER bit if PG was set - val &= ~cr_pg; - stlink_write_debug32(sl, cr_reg, val); - } + uint32_t val, cr_reg, cr_mer, cr_pg; + + if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + cr_mer = 1 << FLASH_CR_MER; + cr_pg = 1 << FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + cr_mer = 1 << FLASH_CR_MER; + cr_pg = 1 << FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2); + cr_pg = (1 << STM32L4_FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_mer = (1 << STM32Gx_FLASH_CR_MER1); + + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + cr_mer |= (1 << STM32Gx_FLASH_CR_MER2); + } + + cr_pg = (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + cr_mer = (1 << FLASH_H7_CR_BER); + cr_pg = (1 << FLASH_H7_CR_PG); + } else { + cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); + } + + stlink_read_debug32(sl, cr_reg, &val); + + if (val & cr_pg) { + // STM32F030 will drop MER bit if PG was set + val &= ~cr_pg; + stlink_write_debug32(sl, cr_reg, val); + } - if (v) { - val |= cr_mer; - } else { - val &= ~cr_mer; - } + if (v) { + val |= cr_mer; + } else { + val &= ~cr_mer; + } - stlink_write_debug32(sl, cr_reg, val); + stlink_write_debug32(sl, cr_reg, val); } static void set_flash_cr_strt(stlink_t *sl, unsigned bank) { - uint32_t val, cr_reg, cr_strt; - - if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - cr_reg = FLASH_F4_CR; - cr_strt = 1 << FLASH_F4_CR_STRT; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - cr_reg = FLASH_F7_CR; - cr_strt = 1 << FLASH_F7_CR_STRT; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - cr_reg = STM32L4_FLASH_CR; - cr_strt = (1 << STM32L4_FLASH_CR_STRT); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_strt = (1 << STM32Gx_FLASH_CR_STRT); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - cr_reg = STM32WB_FLASH_CR; - cr_strt = (1 << STM32WB_FLASH_CR_STRT); - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank==BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id); - } else { - cr_reg = (bank==BANK_1)?FLASH_CR:FLASH_CR2; - cr_strt = (1 << FLASH_CR_STRT); - } - - stlink_read_debug32(sl, cr_reg, &val); - val |= cr_strt; - stlink_write_debug32(sl, cr_reg, val); + uint32_t val, cr_reg, cr_strt; + + if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + cr_reg = FLASH_F4_CR; + cr_strt = 1 << FLASH_F4_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + cr_reg = FLASH_F7_CR; + cr_strt = 1 << FLASH_F7_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + cr_reg = STM32L4_FLASH_CR; + cr_strt = (1 << STM32L4_FLASH_CR_STRT); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_strt = (1 << STM32Gx_FLASH_CR_STRT); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_strt = (1 << STM32WB_FLASH_CR_STRT); + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id); + } else { + cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; + cr_strt = (1 << FLASH_CR_STRT); + } + + stlink_read_debug32(sl, cr_reg, &val); + val |= cr_strt; + stlink_write_debug32(sl, cr_reg, val); } static inline uint32_t read_flash_sr(stlink_t *sl, unsigned bank) { - uint32_t res, sr_reg; - - if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { - sr_reg = (bank==BANK_1)?FLASH_SR:FLASH_SR2; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - sr_reg = FLASH_F4_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - sr_reg = FLASH_F7_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - sr_reg = STM32L4_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - sr_reg = STM32Gx_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - sr_reg = STM32WB_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - sr_reg = (bank==BANK_1)?FLASH_H7_SR1:FLASH_H7_SR2; - } else { - ELOG("method 'read_flash_sr' is unsupported\n"); - return(-1); - } - - stlink_read_debug32(sl, sr_reg, &res); - return(res); + uint32_t res, sr_reg; + + if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { + sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + sr_reg = FLASH_F4_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + sr_reg = FLASH_F7_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + sr_reg = STM32L4_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + sr_reg = STM32Gx_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + sr_reg = STM32WB_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2; + } else { + ELOG("method 'read_flash_sr' is unsupported\n"); + return (-1); + } + + stlink_read_debug32(sl, sr_reg, &res); + return (res); } static inline int write_flash_sr(stlink_t *sl, unsigned bank, uint32_t val) { - uint32_t sr_reg; - - if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { - sr_reg = (bank==BANK_1)?FLASH_SR:FLASH_SR2; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - sr_reg = FLASH_F4_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - sr_reg = FLASH_F7_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - sr_reg = STM32L4_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - sr_reg = STM32Gx_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - sr_reg = STM32WB_FLASH_SR; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - sr_reg = (bank==BANK_1)?FLASH_H7_SR1:FLASH_H7_SR2; - } else { - ELOG("method 'write_flash_sr' is unsupported\n"); - return(-1); - } - - return stlink_write_debug32(sl, sr_reg, val); + uint32_t sr_reg; + + if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { + sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + sr_reg = FLASH_F4_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + sr_reg = FLASH_F7_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + sr_reg = STM32L4_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + sr_reg = STM32Gx_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + sr_reg = STM32WB_FLASH_SR; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2; + } else { + ELOG("method 'write_flash_sr' is unsupported\n"); + return (-1); + } + + return stlink_write_debug32(sl, sr_reg, val); } static inline unsigned int is_flash_busy(stlink_t *sl) { - uint32_t sr_busy_shift; - unsigned int res; - - if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) || - (sl->flash_type == STLINK_FLASH_TYPE_L0)) { - sr_busy_shift = FLASH_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { - sr_busy_shift = FLASH_F4_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { - sr_busy_shift = FLASH_F7_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - sr_busy_shift = STM32L4_FLASH_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - sr_busy_shift = STM32Gx_FLASH_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - sr_busy_shift = STM32WB_FLASH_SR_BSY; - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - sr_busy_shift = FLASH_H7_SR_QW; - } else { - ELOG("method 'is_flash_busy' is unsupported\n"); - return(-1); - } - - res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift); - - if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || - (sl->flash_type == STLINK_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { - res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift); - } - - return(res); + uint32_t sr_busy_shift; + unsigned int res; + + if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) || + (sl->flash_type == STLINK_FLASH_TYPE_L0)) { + sr_busy_shift = FLASH_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) { + sr_busy_shift = FLASH_F4_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) { + sr_busy_shift = FLASH_F7_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + sr_busy_shift = STM32L4_FLASH_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + sr_busy_shift = STM32Gx_FLASH_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + sr_busy_shift = STM32WB_FLASH_SR_BSY; + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + sr_busy_shift = FLASH_H7_SR_QW; + } else { + ELOG("method 'is_flash_busy' is unsupported\n"); + return (-1); + } + + res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift); + + if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || + (sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { + res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift); + } + + return (res); } static void wait_flash_busy(stlink_t *sl) { - // TODO: add some delays here - while (is_flash_busy(sl)) - ; + // TODO: add some delays here + while (is_flash_busy(sl)) + ; } static void wait_flash_busy_progress(stlink_t *sl) { - int i = 0; - fprintf(stdout, "Mass erasing"); - fflush(stdout); - - while (is_flash_busy(sl)) { - usleep(10000); - i++; - - if (i % 100 == 0) { - fprintf(stdout, "."); - fflush(stdout); - } - } - - fprintf(stdout, "\n"); -} - -static void clear_flash_error(stlink_t *sl) -{ - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_F4: - write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_F7: - write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - write_flash_sr(sl, BANK_1, STM32Gx_FLASH_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_L0: - write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_L4: - write_flash_sr(sl, BANK_1, STM32L4_FLASH_SR_ERROR_MASK); - break; - case STLINK_FLASH_TYPE_H7: - write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK); - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK); - } - break; - case STLINK_FLASH_TYPE_WB: - write_flash_sr(sl, BANK_1, STM32WB_FLASH_SR_ERROR_MASK); - break; - default: - break; - } -} - -static int check_flash_error(stlink_t *sl) -{ - uint32_t res = 0; - uint32_t WRPERR, PROGERR, PGAERR; - - WRPERR = PROGERR = PGAERR = 0; - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK; - if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { - res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK; - } - WRPERR = (1 << FLASH_SR_WRPRT_ERR); - PROGERR = (1 << FLASH_SR_PG_ERR); - break; - case STLINK_FLASH_TYPE_F4: - res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK; - WRPERR = (1 << FLASH_F4_SR_WRPERR); - PGAERR = (1 << FLASH_F4_SR_PGAERR); - break; - case STLINK_FLASH_TYPE_F7: - res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK; - WRPERR = (1 << FLASH_F7_SR_WRP_ERR); - PROGERR = (1 << FLASH_F7_SR_PGP_ERR); - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - res = read_flash_sr(sl, BANK_1) & STM32Gx_FLASH_SR_ERROR_MASK; - WRPERR = (1 << STM32Gx_FLASH_SR_WRPERR); - PROGERR = (1 << STM32Gx_FLASH_SR_PROGERR); - PGAERR = (1 << STM32Gx_FLASH_SR_PGAERR); - break; - case STLINK_FLASH_TYPE_L0: - res = read_flash_sr(sl, BANK_1) & STM32L0_FLASH_SR_ERROR_MASK; - WRPERR = (1 << STM32L0_FLASH_SR_WRPERR); - PROGERR = (1 << STM32L0_FLASH_SR_NOTZEROERR); - PGAERR = (1 << STM32L0_FLASH_SR_PGAERR); - break; - case STLINK_FLASH_TYPE_L4: - res = read_flash_sr(sl, BANK_1) & STM32L4_FLASH_SR_ERROR_MASK; - WRPERR = (1 << STM32L4_FLASH_SR_WRPERR); - PROGERR = (1 << STM32L4_FLASH_SR_PROGERR); - PGAERR = (1 << STM32L4_FLASH_SR_PGAERR); - break; - case STLINK_FLASH_TYPE_H7: - res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK; - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK; - } - WRPERR = (1 << FLASH_H7_SR_WRPERR); - break; - case STLINK_FLASH_TYPE_WB: - res = read_flash_sr(sl, BANK_1) & STM32WB_FLASH_SR_ERROR_MASK; - WRPERR = (1 << STM32WB_FLASH_SR_WRPERR); - PROGERR = (1 << STM32WB_FLASH_SR_PROGERR); - PGAERR = (1 << STM32WB_FLASH_SR_PGAERR); - break; - default: - break; + int i = 0; + fprintf(stdout, "Mass erasing"); + fflush(stdout); + + while (is_flash_busy(sl)) { + usleep(10000); + i++; + + if (i % 100 == 0) { + fprintf(stdout, "."); + fflush(stdout); + } + } + + fprintf(stdout, "\n"); +} + +static void clear_flash_error(stlink_t *sl) { + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_F4: + write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_F7: + write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + write_flash_sr(sl, BANK_1, STM32Gx_FLASH_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_L0: + write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_L4: + write_flash_sr(sl, BANK_1, STM32L4_FLASH_SR_ERROR_MASK); + break; + case STLINK_FLASH_TYPE_H7: + write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK); + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK); + } + break; + case STLINK_FLASH_TYPE_WB: + write_flash_sr(sl, BANK_1, STM32WB_FLASH_SR_ERROR_MASK); + break; + default: + break; + } +} + +static int check_flash_error(stlink_t *sl) { + uint32_t res = 0; + uint32_t WRPERR, PROGERR, PGAERR; + + WRPERR = PROGERR = PGAERR = 0; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK; + if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { + res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK; + } + WRPERR = (1 << FLASH_SR_WRPRT_ERR); + PROGERR = (1 << FLASH_SR_PG_ERR); + break; + case STLINK_FLASH_TYPE_F4: + res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK; + WRPERR = (1 << FLASH_F4_SR_WRPERR); + PGAERR = (1 << FLASH_F4_SR_PGAERR); + break; + case STLINK_FLASH_TYPE_F7: + res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK; + WRPERR = (1 << FLASH_F7_SR_WRP_ERR); + PROGERR = (1 << FLASH_F7_SR_PGP_ERR); + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + res = read_flash_sr(sl, BANK_1) & STM32Gx_FLASH_SR_ERROR_MASK; + WRPERR = (1 << STM32Gx_FLASH_SR_WRPERR); + PROGERR = (1 << STM32Gx_FLASH_SR_PROGERR); + PGAERR = (1 << STM32Gx_FLASH_SR_PGAERR); + break; + case STLINK_FLASH_TYPE_L0: + res = read_flash_sr(sl, BANK_1) & STM32L0_FLASH_SR_ERROR_MASK; + WRPERR = (1 << STM32L0_FLASH_SR_WRPERR); + PROGERR = (1 << STM32L0_FLASH_SR_NOTZEROERR); + PGAERR = (1 << STM32L0_FLASH_SR_PGAERR); + break; + case STLINK_FLASH_TYPE_L4: + res = read_flash_sr(sl, BANK_1) & STM32L4_FLASH_SR_ERROR_MASK; + WRPERR = (1 << STM32L4_FLASH_SR_WRPERR); + PROGERR = (1 << STM32L4_FLASH_SR_PROGERR); + PGAERR = (1 << STM32L4_FLASH_SR_PGAERR); + break; + case STLINK_FLASH_TYPE_H7: + res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK; + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK; + } + WRPERR = (1 << FLASH_H7_SR_WRPERR); + break; + case STLINK_FLASH_TYPE_WB: + res = read_flash_sr(sl, BANK_1) & STM32WB_FLASH_SR_ERROR_MASK; + WRPERR = (1 << STM32WB_FLASH_SR_WRPERR); + PROGERR = (1 << STM32WB_FLASH_SR_PROGERR); + PGAERR = (1 << STM32WB_FLASH_SR_PGAERR); + break; + default: + break; + } + + if (res) { + if (WRPERR && (WRPERR & res) == WRPERR) { + ELOG("Flash memory is write protected\n"); + res &= ~WRPERR; + } else if (PROGERR && (PROGERR & res) == PROGERR) { + ELOG("Flash memory contains a non-erased value\n"); + res &= ~PROGERR; + } else if (PGAERR && (PGAERR & res) == PGAERR) { + ELOG("Invalid flash address\n"); + res &= ~PGAERR; } if (res) { - if (WRPERR && (WRPERR&res)==WRPERR) { - ELOG("Flash memory is write protected\n"); - res &= ~WRPERR; - } else if (PROGERR && (PROGERR&res)==PROGERR) { - ELOG("Flash memory contains a non-erased value\n"); - res &= ~PROGERR; - } else if (PGAERR && (PGAERR&res)==PGAERR) { - ELOG("Invalid flash address\n"); - res &= ~PGAERR; - } - - if (res) { - ELOG("Flash programming error: %#010x\n", res); - } - return(-1); + ELOG("Flash programming error: %#010x\n", res); } + return (-1); + } - return(0); + return (0); } static void stop_wdg_in_debug(stlink_t *sl) { - uint32_t dbgmcu_cr; - uint32_t set; - uint32_t value; - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - case STLINK_FLASH_TYPE_G4: - dbgmcu_cr = STM32F0_DBGMCU_CR; - set = (1<flash_type) { - case STLINK_FLASH_TYPE_F0: - case STLINK_FLASH_TYPE_F1_XL: - rcc = STM32F1_RCC_AHBENR; - rcc_dma_mask = STM32F1_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_F4: - case STLINK_FLASH_TYPE_F7: - rcc = STM32F4_RCC_AHB1ENR; - rcc_dma_mask = STM32F4_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_G0: - rcc = STM32G0_RCC_AHBENR; - rcc_dma_mask = STM32G0_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_G4: - case STLINK_FLASH_TYPE_L4: - rcc = STM32G4_RCC_AHB1ENR; - rcc_dma_mask = STM32G4_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_L0: - rcc = STM32L0_RCC_AHBENR; - rcc_dma_mask = STM32L0_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_H7: - rcc = STM32H7_RCC_AHB1ENR; - rcc_dma_mask = STM32H7_RCC_DMAEN; - break; - case STLINK_FLASH_TYPE_WB: - rcc = STM32WB_RCC_AHB1ENR; - rcc_dma_mask = STM32WB_RCC_DMAEN; - break; - default: - return; - } + uint32_t dbgmcu_cr; + uint32_t set; + uint32_t value; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + case STLINK_FLASH_TYPE_G4: + dbgmcu_cr = STM32F0_DBGMCU_CR; + set = + (1 << STM32F0_DBGMCU_CR_IWDG_STOP) | (1 << STM32F0_DBGMCU_CR_WWDG_STOP); + break; + case STLINK_FLASH_TYPE_F4: + case STLINK_FLASH_TYPE_F7: + case STLINK_FLASH_TYPE_L4: + dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1; + set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) | + (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP); + break; + case STLINK_FLASH_TYPE_L0: + case STLINK_FLASH_TYPE_G0: + dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ; + set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) | + (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP); + break; + case STLINK_FLASH_TYPE_H7: + dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ; + set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP); + break; + case STLINK_FLASH_TYPE_WB: + dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1; + set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) | + (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP); + break; + default: + return; + } + + if (!stlink_read_debug32(sl, dbgmcu_cr, &value)) { + stlink_write_debug32(sl, dbgmcu_cr, value | set); + } +} + +static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int bckpRstr) { + uint32_t rcc, rcc_dma_mask, value; + + rcc = rcc_dma_mask = value = 0; + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + rcc = STM32F1_RCC_AHBENR; + rcc_dma_mask = STM32F1_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_F4: + case STLINK_FLASH_TYPE_F7: + rcc = STM32F4_RCC_AHB1ENR; + rcc_dma_mask = STM32F4_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_G0: + rcc = STM32G0_RCC_AHBENR; + rcc_dma_mask = STM32G0_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_G4: + case STLINK_FLASH_TYPE_L4: + rcc = STM32G4_RCC_AHB1ENR; + rcc_dma_mask = STM32G4_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_L0: + rcc = STM32L0_RCC_AHBENR; + rcc_dma_mask = STM32L0_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_H7: + rcc = STM32H7_RCC_AHB1ENR; + rcc_dma_mask = STM32H7_RCC_DMAEN; + break; + case STLINK_FLASH_TYPE_WB: + rcc = STM32WB_RCC_AHB1ENR; + rcc_dma_mask = STM32WB_RCC_DMAEN; + break; + default: + return; + } - if (!stlink_read_debug32(sl, rcc, &value)) { - if (bckpRstr) { - value = (value&(~rcc_dma_mask)) | fl->rcc_dma_bkp; - } else { - fl->rcc_dma_bkp = value&rcc_dma_mask; - value &= ~rcc_dma_mask; - } - stlink_write_debug32(sl, rcc, value); + if (!stlink_read_debug32(sl, rcc, &value)) { + if (bckpRstr) { + value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp; + } else { + fl->rcc_dma_bkp = value & rcc_dma_mask; + value &= ~rcc_dma_mask; } + stlink_write_debug32(sl, rcc, value); + } } static inline void write_flash_ar(stlink_t *sl, uint32_t n, unsigned bank) { - stlink_write_debug32(sl, (bank==BANK_1)?FLASH_AR:FLASH_AR2, n); + stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n); } -static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n, unsigned bank) { - uint32_t cr_reg, psize_shift; - uint32_t x = read_flash_cr(sl, bank); +static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n, + unsigned bank) { + uint32_t cr_reg, psize_shift; + uint32_t x = read_flash_cr(sl, bank); - if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank==BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - psize_shift = FLASH_H7_CR_PSIZE; - } else { - cr_reg = FLASH_F4_CR; - psize_shift = 8; - } + if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + psize_shift = FLASH_H7_CR_PSIZE; + } else { + cr_reg = FLASH_F4_CR; + psize_shift = 8; + } - x &= ~(0x03 << psize_shift); - x |= (n << psize_shift); + x &= ~(0x03 << psize_shift); + x |= (n << psize_shift); #if DEBUG_FLASH - fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n); + fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n); #endif - stlink_write_debug32(sl, cr_reg, x); + stlink_write_debug32(sl, cr_reg, x); } static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, unsigned bank) { - uint32_t cr_reg, snb_mask, snb_shift, ser_shift; - uint32_t x = read_flash_cr(sl, bank); - - if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - cr_reg = (bank==BANK_1)?FLASH_H7_CR1:FLASH_H7_CR2; - snb_mask = FLASH_H7_CR_SNB_MASK; - snb_shift = FLASH_H7_CR_SNB; - ser_shift = FLASH_H7_CR_SER; - } else { - cr_reg = FLASH_F4_CR; - snb_mask = FLASH_F4_CR_SNB_MASK; - snb_shift = FLASH_F4_CR_SNB; - ser_shift = FLASH_F4_CR_SER; - } - - x &= ~snb_mask; - x |= (n << snb_shift); - x |= (1 << ser_shift); + uint32_t cr_reg, snb_mask, snb_shift, ser_shift; + uint32_t x = read_flash_cr(sl, bank); + + if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; + snb_mask = FLASH_H7_CR_SNB_MASK; + snb_shift = FLASH_H7_CR_SNB; + ser_shift = FLASH_H7_CR_SER; + } else { + cr_reg = FLASH_F4_CR; + snb_mask = FLASH_F4_CR_SNB_MASK; + snb_shift = FLASH_F4_CR_SNB; + ser_shift = FLASH_F4_CR_SER; + } + + x &= ~snb_mask; + x |= (n << snb_shift); + x |= (1 << ser_shift); #if DEBUG_FLASH - fprintf(stdout, "SNB:0x%x 0x%x\n", x, n); + fprintf(stdout, "SNB:0x%x 0x%x\n", x, n); #endif - stlink_write_debug32(sl, cr_reg, x); + stlink_write_debug32(sl, cr_reg, x); } static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) { - stlink_write_debug32(sl, STM32L4_FLASH_SR, 0xFFFFFFFF & ~(1 << STM32L4_FLASH_SR_BSY)); - uint32_t x = read_flash_cr(sl, BANK_1); - x &= ~STM32L4_FLASH_CR_OPBITS; - x &= ~STM32L4_FLASH_CR_PAGEMASK; - x &= ~(1 << STM32L4_FLASH_CR_MER1); - x &= ~(1 << STM32L4_FLASH_CR_MER2); - x |= (n << STM32L4_FLASH_CR_PNB); - x |= (uint32_t)(1lu << STM32L4_FLASH_CR_PER); + stlink_write_debug32(sl, STM32L4_FLASH_SR, + 0xFFFFFFFF & ~(1 << STM32L4_FLASH_SR_BSY)); + uint32_t x = read_flash_cr(sl, BANK_1); + x &= ~STM32L4_FLASH_CR_OPBITS; + x &= ~STM32L4_FLASH_CR_PAGEMASK; + x &= ~(1 << STM32L4_FLASH_CR_MER1); + x &= ~(1 << STM32L4_FLASH_CR_MER2); + x |= (n << STM32L4_FLASH_CR_PNB); + x |= (uint32_t)(1lu << STM32L4_FLASH_CR_PER); #if DEBUG_FLASH - fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n); + fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n); #endif - stlink_write_debug32(sl, STM32L4_FLASH_CR, x); + stlink_write_debug32(sl, STM32L4_FLASH_CR, x); } // Delegates to the backends... void stlink_close(stlink_t *sl) { - DLOG("*** stlink_close ***\n"); + DLOG("*** stlink_close ***\n"); - if (!sl) { - return; - } + if (!sl) { + return; + } - sl->backend->close(sl); - free(sl); + sl->backend->close(sl); + free(sl); } int stlink_exit_debug_mode(stlink_t *sl) { - int ret; + int ret; - DLOG("*** stlink_exit_debug_mode ***\n"); - ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY); + DLOG("*** stlink_exit_debug_mode ***\n"); + ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY); - if (ret == -1) { - return(ret); - } + if (ret == -1) { + return (ret); + } - return(sl->backend->exit_debug_mode(sl)); + return (sl->backend->exit_debug_mode(sl)); } int stlink_enter_swd_mode(stlink_t *sl) { - DLOG("*** stlink_enter_swd_mode ***\n"); - return(sl->backend->enter_swd_mode(sl)); + DLOG("*** stlink_enter_swd_mode ***\n"); + return (sl->backend->enter_swd_mode(sl)); } // Force the core into the debug mode -> halted state. int stlink_force_debug(stlink_t *sl) { - DLOG("*** stlink_force_debug_mode ***\n"); - int res = sl->backend->force_debug(sl); - // Stop the watchdogs in the halted state for suppress target reboot - stop_wdg_in_debug(sl); - return(res); + DLOG("*** stlink_force_debug_mode ***\n"); + int res = sl->backend->force_debug(sl); + // Stop the watchdogs in the halted state for suppress target reboot + stop_wdg_in_debug(sl); + return (res); } int stlink_exit_dfu_mode(stlink_t *sl) { - DLOG("*** stlink_exit_dfu_mode ***\n"); - return(sl->backend->exit_dfu_mode(sl)); + DLOG("*** stlink_exit_dfu_mode ***\n"); + return (sl->backend->exit_dfu_mode(sl)); } int stlink_core_id(stlink_t *sl) { - int ret; + int ret; - DLOG("*** stlink_core_id ***\n"); - ret = sl->backend->core_id(sl); + DLOG("*** stlink_core_id ***\n"); + ret = sl->backend->core_id(sl); - if (ret == -1) { - ELOG("Failed to read core_id\n"); - return(ret); - } + if (ret == -1) { + ELOG("Failed to read core_id\n"); + return (ret); + } - if (sl->verbose > 2) { - stlink_print_data(sl); - } + if (sl->verbose > 2) { + stlink_print_data(sl); + } - DLOG("core_id = 0x%08x\n", sl->core_id); - return(ret); + DLOG("core_id = 0x%08x\n", sl->core_id); + return (ret); } // stlink_chip_id() is called by stlink_load_device_params() // do not call this procedure directly. int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) { - int ret; - cortex_m3_cpuid_t cpu_id; - - // Read the CPU ID to determine where to read the core id - if (stlink_cpu_id(sl, &cpu_id) || - cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) { - ELOG("Can not connect to target. Please use \'connect under reset\' and try again\n"); - return -1; - } - - /* - * the chip_id register in the reference manual have - * DBGMCU_IDCODE / DBG_IDCODE name - * - */ - - if ((sl->core_id == STM32H7_CORE_ID || - sl->core_id == STM32H7_CORE_ID_JTAG) && - cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) { - // STM32H7 chipid in 0x5c001000 (RM0433 pg3189) - ret = stlink_read_debug32(sl, 0x5c001000, chip_id); - } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 || - cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) { - // STM32F0 (RM0091, pg914; RM0360, pg713) - // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917) - // STM32G0 (RM0444, pg1367) - ret = stlink_read_debug32(sl, 0x40015800, chip_id); - } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) { - // STM32L5 (RM0438, pg2157) - ret = stlink_read_debug32(sl, 0xE0044000, chip_id); - } else /* СM3, СM4, CM7 */ { - // default chipid address - - // STM32F1 (RM0008, pg1087; RM0041, pg681) - // STM32F2 (RM0033, pg1326) - // STM32F3 (RM0316, pg1095; RM0313, pg874) - // STM32F7 (RM0385, pg1676; RM0410, pg1912) - // STM32L1 (RM0038, pg861) - // STM32L4 (RM0351, pg1840; RM0394, pg1560) - // STM32G4 (RM0440, pg2086) - // STM32WB (RM0434, pg1406) - ret = stlink_read_debug32(sl, 0xE0042000, chip_id); - } - - if (ret || !(*chip_id)) { - *chip_id = 0; - ELOG("Could not find chip id!\n"); - } else { - *chip_id = (*chip_id) & 0xfff; - - // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for F2/F4 - if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) { - *chip_id = 0x413; - } - } - - return(ret); + int ret; + cortex_m3_cpuid_t cpu_id; + + // Read the CPU ID to determine where to read the core id + if (stlink_cpu_id(sl, &cpu_id) || + cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) { + ELOG("Can not connect to target. Please use \'connect under reset\' and " + "try again\n"); + return -1; + } + + /* + * the chip_id register in the reference manual have + * DBGMCU_IDCODE / DBG_IDCODE name + * + */ + + if ((sl->core_id == STM32H7_CORE_ID || sl->core_id == STM32H7_CORE_ID_JTAG) && + cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) { + // STM32H7 chipid in 0x5c001000 (RM0433 pg3189) + ret = stlink_read_debug32(sl, 0x5c001000, chip_id); + } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 || + cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) { + // STM32F0 (RM0091, pg914; RM0360, pg713) + // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917) + // STM32G0 (RM0444, pg1367) + ret = stlink_read_debug32(sl, 0x40015800, chip_id); + } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) { + // STM32L5 (RM0438, pg2157) + ret = stlink_read_debug32(sl, 0xE0044000, chip_id); + } else /* СM3, СM4, CM7 */ { + // default chipid address + + // STM32F1 (RM0008, pg1087; RM0041, pg681) + // STM32F2 (RM0033, pg1326) + // STM32F3 (RM0316, pg1095; RM0313, pg874) + // STM32F7 (RM0385, pg1676; RM0410, pg1912) + // STM32L1 (RM0038, pg861) + // STM32L4 (RM0351, pg1840; RM0394, pg1560) + // STM32G4 (RM0440, pg2086) + // STM32WB (RM0434, pg1406) + ret = stlink_read_debug32(sl, 0xE0042000, chip_id); + } + + if (ret || !(*chip_id)) { + *chip_id = 0; + ELOG("Could not find chip id!\n"); + } else { + *chip_id = (*chip_id) & 0xfff; + + // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for + // F2/F4 + if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) { + *chip_id = 0x413; + } + } + + return (ret); } /** @@ -1553,21 +1558,21 @@ int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) { * @param cpuid pointer to the result object */ int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) { - uint32_t raw; - - if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) { - cpuid->implementer_id = 0; - cpuid->variant = 0; - cpuid->part = 0; - cpuid->revision = 0; - return(-1); - } + uint32_t raw; - cpuid->implementer_id = (raw >> 24) & 0x7f; - cpuid->variant = (raw >> 20) & 0xf; - cpuid->part = (raw >> 4) & 0xfff; - cpuid->revision = raw & 0xf; - return(0); + if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) { + cpuid->implementer_id = 0; + cpuid->variant = 0; + cpuid->part = 0; + cpuid->revision = 0; + return (-1); + } + + cpuid->implementer_id = (raw >> 24) & 0x7f; + cpuid->variant = (raw >> 20) & 0xf; + cpuid->part = (raw >> 4) & 0xfff; + cpuid->revision = raw & 0xf; + return (0); } /** @@ -1576,256 +1581,269 @@ int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) { * @return 0 for success, or -1 for unsupported core type. */ int stlink_load_device_params(stlink_t *sl) { - // This seems to normally work so is unnecessary info for a normal user. - // Demoted to debug. -- REW - DLOG("Loading device parameters....\n"); - const struct stlink_chipid_params *params = NULL; - stlink_core_id(sl); - uint32_t flash_size; - - if (stlink_chip_id(sl, &sl->chip_id)) { - return(-1); - } + // This seems to normally work so is unnecessary info for a normal user. + // Demoted to debug. -- REW + DLOG("Loading device parameters....\n"); + const struct stlink_chipid_params *params = NULL; + stlink_core_id(sl); + uint32_t flash_size; + + if (stlink_chip_id(sl, &sl->chip_id)) { + return (-1); + } + + params = stlink_chipid_get_params(sl->chip_id); + + if (params == NULL) { + WLOG("unknown chip id! %#x\n", sl->chip_id); + return (-1); + } + + if (params->flash_type == STLINK_FLASH_TYPE_UNKNOWN) { + WLOG("Invalid flash type, please check device declaration\n"); + sl->flash_size = 0; + return (0); + } + + // These are fixed... + sl->flash_base = STM32_FLASH_BASE; + sl->sram_base = STM32_SRAM_BASE; + stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size); + + if (params->flash_size_reg & 2) { + flash_size = flash_size >> 16; + } + + flash_size = flash_size & 0xffff; + + if ((sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM || + sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW || + sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS) && + (flash_size == 0)) { + sl->flash_size = 128 * 1024; + } else if (sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2) { + sl->flash_size = (flash_size & 0xff) * 1024; + } else if ((sl->chip_id & 0xFFF) == STLINK_CHIPID_STM32_L1_HIGH) { + // 0 is 384k and 1 is 256k + if (flash_size == 0) { + sl->flash_size = 384 * 1024; + } else { + sl->flash_size = 256 * 1024; + } + } else { + sl->flash_size = flash_size * 1024; + } + + sl->flash_type = params->flash_type; + sl->flash_pgsz = params->flash_pagesize; + sl->sram_size = params->sram_size; + sl->sys_base = params->bootrom_base; + sl->sys_size = params->bootrom_size; + sl->option_base = params->option_base; + sl->option_size = params->option_size; + sl->chip_flags = params->flags; + + // medium and low devices have the same chipid. ram size depends on flash + // size. STM32F100xx datasheet Doc ID 16455 Table 2 + if (sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW && + sl->flash_size < 64 * 1024) { + sl->sram_size = 0x1000; + } + + if (sl->chip_id == STLINK_CHIPID_STM32_G4_CAT3) { + uint32_t flash_optr; + stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, &flash_optr); + + if (!(flash_optr & (1 << STM32G4_FLASH_OPTR_DBANK))) { + sl->flash_pgsz <<= 1; + } + } + + // H7 devices with small flash has one bank + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK && + sl->flash_type == STLINK_FLASH_TYPE_H7) { + if ((flash_size / sl->flash_pgsz) <= 1) + sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK; + } + + ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n", + params->description, (unsigned)(sl->sram_size / 1024), + (unsigned)(sl->flash_size / 1024), + (sl->flash_pgsz < 1024) ? (unsigned)(sl->flash_pgsz) + : (unsigned)(sl->flash_pgsz / 1024), + (sl->flash_pgsz < 1024) ? "byte" : "KiB"); + + return (0); +} - params = stlink_chipid_get_params(sl->chip_id); +int stlink_jtag_reset(stlink_t *sl, int value) { + DLOG("*** stlink_jtag_reset ***\n"); + return (sl->backend->jtag_reset(sl, value)); +} - if (params == NULL) { - WLOG("unknown chip id! %#x\n", sl->chip_id); - return(-1); +int stlink_soft_reset(stlink_t *sl, int halt_on_reset) { + int ret; + unsigned timeout; + uint32_t dhcsr, dfsr; + + DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : ""); + + // halt core and enable debugging (if not already done) + // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6) + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | + STLINK_REG_DHCSR_C_DEBUGEN); + + // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10) + if (halt_on_reset) { + stlink_write_debug32( + sl, STLINK_REG_CM3_DEMCR, + STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR | + STLINK_REG_CM3_DEMCR_VC_BUSERR | STLINK_REG_CM3_DEMCR_VC_CORERESET); + + // clear VCATCH in the DFSR register + stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH); + } else { + stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR, + STLINK_REG_CM3_DEMCR_TRCENA | + STLINK_REG_CM3_DEMCR_VC_HARDERR | + STLINK_REG_CM3_DEMCR_VC_BUSERR); + } + + // clear S_RESET_ST in the DHCSR register + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + + // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23) + ret = stlink_write_debug32(sl, STLINK_REG_AIRCR, + STLINK_REG_AIRCR_VECTKEY | + STLINK_REG_AIRCR_SYSRESETREQ); + if (ret) { + ELOG("Soft reset failed: error write to AIRCR\n"); + return (ret); + } + + // waiting for a reset within 500ms + // DDI0337E, p. 10-4, Debug Halting Control and Status Register + timeout = time_ms() + 500; + while (time_ms() < timeout) { + // DDI0337E, p. 10-4, Debug Halting Control and Status Register + dhcsr = STLINK_REG_DHCSR_S_RESET_ST; + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { + if (halt_on_reset) { + // waiting halt by the SYSRESETREQ exception + // DDI0403E, p. C1-699, Debug Fault Status Register + dfsr = 0; + stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr); + if ((dfsr & STLINK_REG_DFSR_VCATCH) == 0) { + continue; + } + } + timeout = 0; + break; } + } - if (params->flash_type == STLINK_FLASH_TYPE_UNKNOWN) { - WLOG("Invalid flash type, please check device declaration\n"); - sl->flash_size = 0; - return(0); - } + // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5) + stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR); - // These are fixed... - sl->flash_base = STM32_FLASH_BASE; - sl->sram_base = STM32_SRAM_BASE; - stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size); + if (timeout) { + ELOG("Soft reset failed: timeout\n"); + return (-1); + } - if (params->flash_size_reg & 2) { - flash_size = flash_size >> 16; - } + return (0); +} - flash_size = flash_size & 0xffff; - - if ((sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM || - sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW || - sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS) && (flash_size == 0)) { - sl->flash_size = 128 * 1024; - } else if (sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2) { - sl->flash_size = (flash_size & 0xff) * 1024; - } else if ((sl->chip_id & 0xFFF) == STLINK_CHIPID_STM32_L1_HIGH) { - // 0 is 384k and 1 is 256k - if (flash_size == 0) { - sl->flash_size = 384 * 1024; - } else { - sl->flash_size = 256 * 1024; - } - } else { - sl->flash_size = flash_size * 1024; - } +int stlink_reset(stlink_t *sl, enum reset_type type) { + uint32_t dhcsr; + unsigned timeout; + + DLOG("*** stlink_reset ***\n"); + + if (type == RESET_AUTO) { + // clear S_RESET_ST in DHCSR register for reset state detection + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + } - sl->flash_type = params->flash_type; - sl->flash_pgsz = params->flash_pagesize; - sl->sram_size = params->sram_size; - sl->sys_base = params->bootrom_base; - sl->sys_size = params->bootrom_size; - sl->option_base = params->option_base; - sl->option_size = params->option_size; - sl->chip_flags = params->flags; - - // medium and low devices have the same chipid. ram size depends on flash size. - // STM32F100xx datasheet Doc ID 16455 Table 2 - if (sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW && sl->flash_size < 64 * 1024) { - sl->sram_size = 0x1000; + if (type == RESET_HARD || type == RESET_AUTO) { + // hardware target reset + if (sl->version.stlink_v > 1) { + stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW); + // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) + usleep(100); + stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH); + } + if (sl->backend->reset(sl)) { + return (-1); } + usleep(10000); + } - if (sl->chip_id == STLINK_CHIPID_STM32_G4_CAT3) { - uint32_t flash_optr; - stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, &flash_optr); + if (type == RESET_AUTO) { + /* Check if the S_RESET_ST bit is set in DHCSR + * This means that a reset has occurred + * DDI0337E, p. 10-4, Debug Halting Control and Status Register */ + + dhcsr = 0; + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { + // reset not done yet + // try reset through AIRCR so that NRST does not need to be connected - if (!(flash_optr & (1 << STM32G4_FLASH_OPTR_DBANK))) { sl->flash_pgsz <<= 1; } + WLOG("NRST is not connected\n"); + DLOG("Using reset through SYSRESETREQ\n"); + return stlink_soft_reset(sl, 0); } - // H7 devices with small flash has one bank - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK && sl->flash_type == STLINK_FLASH_TYPE_H7) { - if ((flash_size/sl->flash_pgsz) <= 1) - sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK; + // waiting for reset the S_RESET_ST bit within 500ms + timeout = time_ms() + 500; + while (time_ms() < timeout) { + dhcsr = STLINK_REG_DHCSR_S_RESET_ST; + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) + return (0); } - ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n", - params->description, (unsigned)(sl->sram_size / 1024), (unsigned)(sl->flash_size / 1024), - (sl->flash_pgsz < 1024) ? (unsigned)(sl->flash_pgsz) : (unsigned)(sl->flash_pgsz / 1024), - (sl->flash_pgsz < 1024) ? "byte" : "KiB"); + return (-1); + } - return(0); + if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) { + return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT)); + } + + return (0); } +int stlink_run(stlink_t *sl, enum run_type type) { + struct stlink_reg rr; + DLOG("*** stlink_run ***\n"); + + /* Make sure we are in Thumb mode + * Cortex-M chips don't support ARM mode instructions + * xPSR may be incorrect if the vector table has invalid data */ + stlink_read_reg(sl, 16, &rr); + if ((rr.xpsr & (1 << 24)) == 0) { + ILOG("Go to Thumb mode\n"); + stlink_write_reg(sl, rr.xpsr | (1 << 24), 16); + } -int stlink_jtag_reset(stlink_t *sl, int value) { - DLOG("*** stlink_jtag_reset ***\n"); - return(sl->backend->jtag_reset(sl, value)); + return (sl->backend->run(sl, type)); } -int stlink_soft_reset(stlink_t *sl, int halt_on_reset) { - int ret; - unsigned timeout; - uint32_t dhcsr, dfsr; - - DLOG("*** stlink_soft_reset %s***\n", halt_on_reset?"(halt) ":""); +int stlink_set_swdclk(stlink_t *sl, int freq_khz) { + DLOG("*** set_swdclk ***\n"); + return (sl->backend->set_swdclk(sl, freq_khz)); +} - // halt core and enable debugging (if not already done) - // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6) - stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | - STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_DEBUGEN); +int stlink_status(stlink_t *sl) { + int ret; - // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10) - if (halt_on_reset) { - stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR, STLINK_REG_CM3_DEMCR_TRCENA | - STLINK_REG_CM3_DEMCR_VC_HARDERR | STLINK_REG_CM3_DEMCR_VC_BUSERR | - STLINK_REG_CM3_DEMCR_VC_CORERESET); - - // clear VCATCH in the DFSR register - stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH); - } else { - stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR, STLINK_REG_CM3_DEMCR_TRCENA | - STLINK_REG_CM3_DEMCR_VC_HARDERR | STLINK_REG_CM3_DEMCR_VC_BUSERR); - } - - // clear S_RESET_ST in the DHCSR register - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - - // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23) - ret = stlink_write_debug32(sl, STLINK_REG_AIRCR, STLINK_REG_AIRCR_VECTKEY | - STLINK_REG_AIRCR_SYSRESETREQ); - if (ret) { - ELOG("Soft reset failed: error write to AIRCR\n"); - return(ret); - } - - // waiting for a reset within 500ms - // DDI0337E, p. 10-4, Debug Halting Control and Status Register - timeout = time_ms() + 500; - while (time_ms() < timeout) { - // DDI0337E, p. 10-4, Debug Halting Control and Status Register - dhcsr = STLINK_REG_DHCSR_S_RESET_ST; - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr&STLINK_REG_DHCSR_S_RESET_ST) == 0) { - if (halt_on_reset) { - // waiting halt by the SYSRESETREQ exception - // DDI0403E, p. C1-699, Debug Fault Status Register - dfsr = 0; - stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr); - if ((dfsr&STLINK_REG_DFSR_VCATCH) == 0) { - continue; - } - } - timeout = 0; - break; - } - } - - // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5) - stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR); - - if (timeout) { - ELOG("Soft reset failed: timeout\n"); - return(-1); - } - - return(0); -} - -int stlink_reset(stlink_t *sl, enum reset_type type) { - uint32_t dhcsr; - unsigned timeout; - - DLOG("*** stlink_reset ***\n"); - - if (type == RESET_AUTO) { - // clear S_RESET_ST in DHCSR register for reset state detection - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - } - - if (type == RESET_HARD || type == RESET_AUTO) { - // hardware target reset - if (sl->version.stlink_v > 1) { - stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW); - // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) - usleep(100); - stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH); - } - if (sl->backend->reset(sl)) { return(-1); } - usleep(10000); - } - - if (type == RESET_AUTO) { - /* Check if the S_RESET_ST bit is set in DHCSR - * This means that a reset has occurred - * DDI0337E, p. 10-4, Debug Halting Control and Status Register */ - - dhcsr = 0; - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { - // reset not done yet - // try reset through AIRCR so that NRST does not need to be connected - - WLOG("NRST is not connected\n"); - DLOG("Using reset through SYSRESETREQ\n"); - return stlink_soft_reset(sl, 0); - } - - // waiting for reset the S_RESET_ST bit within 500ms - timeout = time_ms() + 500; - while (time_ms() < timeout) { - dhcsr = STLINK_REG_DHCSR_S_RESET_ST; - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr&STLINK_REG_DHCSR_S_RESET_ST) == 0) - return(0); - } - - return(-1); - } - - if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) { - return stlink_soft_reset(sl, (type==RESET_SOFT_AND_HALT)); - } - - return(0); -} - -int stlink_run(stlink_t *sl, enum run_type type) { - struct stlink_reg rr; - DLOG("*** stlink_run ***\n"); - - /* Make sure we are in Thumb mode - * Cortex-M chips don't support ARM mode instructions - * xPSR may be incorrect if the vector table has invalid data */ - stlink_read_reg(sl, 16, &rr); - if ((rr.xpsr & (1 << 24)) == 0) { - ILOG("Go to Thumb mode\n"); - stlink_write_reg(sl, rr.xpsr | (1 << 24), 16); - } - - return(sl->backend->run(sl, type)); -} - -int stlink_set_swdclk(stlink_t *sl, int freq_khz) { - DLOG("*** set_swdclk ***\n"); - return(sl->backend->set_swdclk(sl, freq_khz)); -} - -int stlink_status(stlink_t *sl) { - int ret; - - DLOG("*** stlink_status ***\n"); - ret = sl->backend->status(sl); - stlink_core_stat(sl); - return(ret); -} + DLOG("*** stlink_status ***\n"); + ret = sl->backend->status(sl); + stlink_core_stat(sl); + return (ret); +} /** * Decode the version bits, originally from -sg, verified with usb @@ -1833,1109 +1851,1192 @@ int stlink_status(stlink_t *sl) { * @param slv output parsed version object */ void _parse_version(stlink_t *sl, stlink_version_t *slv) { - sl->version.flags = 0; - - if (sl->version.stlink_v < 3) { - uint32_t b0 = sl->q_buf[0]; // lsb - uint32_t b1 = sl->q_buf[1]; - uint32_t b2 = sl->q_buf[2]; - uint32_t b3 = sl->q_buf[3]; - uint32_t b4 = sl->q_buf[4]; - uint32_t b5 = sl->q_buf[5]; // msb - - // b0 b1 || b2 b3 | b4 b5 - // 4b | 6b | 6b || 2B | 2B - // stlink_v | jtag_v | swim_v || st_vid | stlink_pid - - slv->stlink_v = (b0 & 0xf0) >> 4; - slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6); - slv->swim_v = b1 & 0x3f; - slv->st_vid = (b3 << 8) | b2; - slv->stlink_pid = (b5 << 8) | b4; - - // ST-LINK/V1 from J11 switch to api-v2 (and support SWD) - if (slv->stlink_v == 1) { - slv->jtag_api = slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1; - } else { - slv->jtag_api = STLINK_JTAG_API_V2; - - // preferred API to get last R/W status from J15 - if (sl->version.jtag_v >= 15) { - sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2; - } - - if (sl->version.jtag_v >= 13) { - sl->version.flags |= STLINK_F_HAS_TRACE; - sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY; - } - } + sl->version.flags = 0; + + if (sl->version.stlink_v < 3) { + uint32_t b0 = sl->q_buf[0]; // lsb + uint32_t b1 = sl->q_buf[1]; + uint32_t b2 = sl->q_buf[2]; + uint32_t b3 = sl->q_buf[3]; + uint32_t b4 = sl->q_buf[4]; + uint32_t b5 = sl->q_buf[5]; // msb + + // b0 b1 || b2 b3 | b4 b5 + // 4b | 6b | 6b || 2B | 2B + // stlink_v | jtag_v | swim_v || st_vid | stlink_pid + + slv->stlink_v = (b0 & 0xf0) >> 4; + slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6); + slv->swim_v = b1 & 0x3f; + slv->st_vid = (b3 << 8) | b2; + slv->stlink_pid = (b5 << 8) | b4; + + // ST-LINK/V1 from J11 switch to api-v2 (and support SWD) + if (slv->stlink_v == 1) { + slv->jtag_api = + slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1; } else { - // V3 uses different version format, for reference see OpenOCD source - // (that was written from docs available from ST under NDA): - // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965 - slv->stlink_v = sl->q_buf[0]; - slv->swim_v = sl->q_buf[1]; - slv->jtag_v = sl->q_buf[2]; - slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]); - slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]); - slv->jtag_api = STLINK_JTAG_API_V3; - /* preferred API to get last R/W status */ + slv->jtag_api = STLINK_JTAG_API_V2; + + // preferred API to get last R/W status from J15 + if (sl->version.jtag_v >= 15) { sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2; - sl->version.flags |= STLINK_F_HAS_TRACE; - sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY; - } + } - return; + if (sl->version.jtag_v >= 13) { + sl->version.flags |= STLINK_F_HAS_TRACE; + sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY; + } + } + } else { + // V3 uses different version format, for reference see OpenOCD source + // (that was written from docs available from ST under NDA): + // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965 + slv->stlink_v = sl->q_buf[0]; + slv->swim_v = sl->q_buf[1]; + slv->jtag_v = sl->q_buf[2]; + slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]); + slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]); + slv->jtag_api = STLINK_JTAG_API_V3; + /* preferred API to get last R/W status */ + sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2; + sl->version.flags |= STLINK_F_HAS_TRACE; + sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY; + } + + return; } int stlink_version(stlink_t *sl) { - DLOG("*** looking up stlink version\n"); + DLOG("*** looking up stlink version\n"); - if (sl->backend->version(sl)) { - return(-1); - } + if (sl->backend->version(sl)) { + return (-1); + } - _parse_version(sl, &sl->version); + _parse_version(sl, &sl->version); - DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, STLINK_USB_VID_ST); - DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid); - DLOG("stlink version = 0x%x\n", sl->version.stlink_v); - DLOG("jtag version = 0x%x\n", sl->version.jtag_v); - DLOG("swim version = 0x%x\n", sl->version.swim_v); + DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, + STLINK_USB_VID_ST); + DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid); + DLOG("stlink version = 0x%x\n", sl->version.stlink_v); + DLOG("jtag version = 0x%x\n", sl->version.jtag_v); + DLOG("swim version = 0x%x\n", sl->version.swim_v); - if (sl->version.jtag_v == 0) { - DLOG(" notice: the firmware doesn't support a jtag/swd interface\n"); - } + if (sl->version.jtag_v == 0) { + DLOG(" notice: the firmware doesn't support a jtag/swd interface\n"); + } - if (sl->version.swim_v == 0) { - DLOG(" notice: the firmware doesn't support a swim interface\n"); - } + if (sl->version.swim_v == 0) { + DLOG(" notice: the firmware doesn't support a swim interface\n"); + } - return(0); + return (0); } int stlink_target_voltage(stlink_t *sl) { - int voltage = -1; - DLOG("*** reading target voltage\n"); + int voltage = -1; + DLOG("*** reading target voltage\n"); - if (sl->backend->target_voltage != NULL) { - voltage = sl->backend->target_voltage(sl); + if (sl->backend->target_voltage != NULL) { + voltage = sl->backend->target_voltage(sl); - if (voltage != -1) { - DLOG("target voltage = %imV\n", voltage); - } else { - DLOG("error reading target voltage\n"); - } + if (voltage != -1) { + DLOG("target voltage = %imV\n", voltage); } else { - DLOG("reading voltage not supported by backend\n"); + DLOG("error reading target voltage\n"); } + } else { + DLOG("reading voltage not supported by backend\n"); + } - return(voltage); + return (voltage); } int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { - int ret; + int ret; - ret = sl->backend->read_debug32(sl, addr, data); - if (!ret) - DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr); + ret = sl->backend->read_debug32(sl, addr, data); + if (!ret) + DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr); - return(ret); + return (ret); } int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { - DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr); - return sl->backend->write_debug32(sl, addr, data); + DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr); + return sl->backend->write_debug32(sl, addr, data); } int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { - DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr); + DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr); - if (len % 4 != 0) { - ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); - return(-1); - } + if (len % 4 != 0) { + ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); + return (-1); + } - return(sl->backend->write_mem32(sl, addr, len)); + return (sl->backend->write_mem32(sl, addr, len)); } int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { - DLOG("*** stlink_read_mem32 ***\n"); + DLOG("*** stlink_read_mem32 ***\n"); - if (len % 4 != 0) { // !!! never ever: fw gives just wrong values - ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); - return(-1); - } + if (len % 4 != 0) { // !!! never ever: fw gives just wrong values + ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); + return (-1); + } - return(sl->backend->read_mem32(sl, addr, len)); + return (sl->backend->read_mem32(sl, addr, len)); } int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { - DLOG("*** stlink_write_mem8 ***\n"); + DLOG("*** stlink_write_mem8 ***\n"); - if (len > 0x40) { // !!! never ever: Writing more then 0x40 bytes gives unexpected behaviour - ELOG("Data length > 64: +%d byte.\n", len); - return(-1); - } + if (len > 0x40) { // !!! never ever: Writing more then 0x40 bytes gives + // unexpected behaviour + ELOG("Data length > 64: +%d byte.\n", len); + return (-1); + } - return(sl->backend->write_mem8(sl, addr, len)); + return (sl->backend->write_mem8(sl, addr, len)); } int stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { - DLOG("*** stlink_read_all_regs ***\n"); - return(sl->backend->read_all_regs(sl, regp)); + DLOG("*** stlink_read_all_regs ***\n"); + return (sl->backend->read_all_regs(sl, regp)); } int stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { - DLOG("*** stlink_read_all_unsupported_regs ***\n"); - return(sl->backend->read_all_unsupported_regs(sl, regp)); + DLOG("*** stlink_read_all_unsupported_regs ***\n"); + return (sl->backend->read_all_unsupported_regs(sl, regp)); } int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) { - DLOG("*** stlink_write_reg\n"); - return(sl->backend->write_reg(sl, reg, idx)); + DLOG("*** stlink_write_reg\n"); + return (sl->backend->write_reg(sl, reg, idx)); } int stlink_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) { - DLOG("*** stlink_read_reg\n"); - DLOG(" (%d) ***\n", r_idx); + DLOG("*** stlink_read_reg\n"); + DLOG(" (%d) ***\n", r_idx); - if (r_idx > 20 || r_idx < 0) { - fprintf(stderr, "Error: register index must be in [0..20]\n"); - return(-1); - } + if (r_idx > 20 || r_idx < 0) { + fprintf(stderr, "Error: register index must be in [0..20]\n"); + return (-1); + } - return(sl->backend->read_reg(sl, r_idx, regp)); + return (sl->backend->read_reg(sl, r_idx, regp)); } -int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) { - int r_convert; +int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, + struct stlink_reg *regp) { + int r_convert; - DLOG("*** stlink_read_unsupported_reg\n"); - DLOG(" (%d) ***\n", r_idx); + DLOG("*** stlink_read_unsupported_reg\n"); + DLOG(" (%d) ***\n", r_idx); - /* Convert to values used by STLINK_REG_DCRSR */ - if (r_idx >= 0x1C && r_idx <= 0x1F) { // primask, basepri, faultmask, or control - r_convert = 0x14; - } else if (r_idx == 0x40) { // FPSCR - r_convert = 0x21; - } else if (r_idx >= 0x20 && r_idx < 0x40) { - r_convert = 0x40 + (r_idx - 0x20); - } else { - fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); - return(-1); - } + /* Convert to values used by STLINK_REG_DCRSR */ + if (r_idx >= 0x1C && + r_idx <= 0x1F) { // primask, basepri, faultmask, or control + r_convert = 0x14; + } else if (r_idx == 0x40) { // FPSCR + r_convert = 0x21; + } else if (r_idx >= 0x20 && r_idx < 0x40) { + r_convert = 0x40 + (r_idx - 0x20); + } else { + fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); + return (-1); + } - return(sl->backend->read_unsupported_reg(sl, r_convert, regp)); + return (sl->backend->read_unsupported_reg(sl, r_convert, regp)); } -int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, struct stlink_reg *regp) { - int r_convert; +int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, + struct stlink_reg *regp) { + int r_convert; - DLOG("*** stlink_write_unsupported_reg\n"); - DLOG(" (%d) ***\n", r_idx); + DLOG("*** stlink_write_unsupported_reg\n"); + DLOG(" (%d) ***\n", r_idx); - /* Convert to values used by STLINK_REG_DCRSR */ - if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ - r_convert = r_idx; // the backend function handles this - } else if (r_idx == 0x40) { // FPSCR - r_convert = 0x21; - } else if (r_idx >= 0x20 && r_idx < 0x40) { - r_convert = 0x40 + (r_idx - 0x20); - } else { - fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); - return(-1); - } + /* Convert to values used by STLINK_REG_DCRSR */ + if (r_idx >= 0x1C && + r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ + r_convert = r_idx; // the backend function handles this + } else if (r_idx == 0x40) { // FPSCR + r_convert = 0x21; + } else if (r_idx >= 0x20 && r_idx < 0x40) { + r_convert = 0x40 + (r_idx - 0x20); + } else { + fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); + return (-1); + } - return(sl->backend->write_unsupported_reg(sl, val, r_convert, regp)); + return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp)); } bool stlink_is_core_halted(stlink_t *sl) { - stlink_status(sl); - return(sl->core_stat == TARGET_HALTED); + stlink_status(sl); + return (sl->core_stat == TARGET_HALTED); } int stlink_step(stlink_t *sl) { - DLOG("*** stlink_step ***\n"); - return(sl->backend->step(sl)); + DLOG("*** stlink_step ***\n"); + return (sl->backend->step(sl)); } int stlink_current_mode(stlink_t *sl) { - int mode = sl->backend->current_mode(sl); - - switch (mode) { - case STLINK_DEV_DFU_MODE: - DLOG("stlink current mode: dfu\n"); - return(mode); - case STLINK_DEV_DEBUG_MODE: - DLOG("stlink current mode: debug (jtag or swd)\n"); - return(mode); - case STLINK_DEV_MASS_MODE: - DLOG("stlink current mode: mass\n"); - return(mode); - } + int mode = sl->backend->current_mode(sl); - DLOG("stlink mode: unknown!\n"); - return(STLINK_DEV_UNKNOWN_MODE); -} + switch (mode) { + case STLINK_DEV_DFU_MODE: + DLOG("stlink current mode: dfu\n"); + return (mode); + case STLINK_DEV_DEBUG_MODE: + DLOG("stlink current mode: debug (jtag or swd)\n"); + return (mode); + case STLINK_DEV_MASS_MODE: + DLOG("stlink current mode: mass\n"); + return (mode); + } -int stlink_trace_enable(stlink_t* sl, uint32_t frequency) { - DLOG("*** stlink_trace_enable ***\n"); - return(sl->backend->trace_enable(sl, frequency)); + DLOG("stlink mode: unknown!\n"); + return (STLINK_DEV_UNKNOWN_MODE); } -int stlink_trace_disable(stlink_t* sl) { - DLOG("*** stlink_trace_disable ***\n"); - return(sl->backend->trace_disable(sl)); +int stlink_trace_enable(stlink_t *sl, uint32_t frequency) { + DLOG("*** stlink_trace_enable ***\n"); + return (sl->backend->trace_enable(sl, frequency)); } -int stlink_trace_read(stlink_t* sl, uint8_t* buf, size_t size) { - return(sl->backend->trace_read(sl, buf, size)); +int stlink_trace_disable(stlink_t *sl) { + DLOG("*** stlink_trace_disable ***\n"); + return (sl->backend->trace_disable(sl)); } +int stlink_trace_read(stlink_t *sl, uint8_t *buf, size_t size) { + return (sl->backend->trace_read(sl, buf, size)); +} // End of delegates.... Common code below here... - - // same as above with entrypoint. void stlink_run_at(stlink_t *sl, stm32_addr_t addr) { - stlink_write_reg(sl, addr, 15); /* pc register */ - stlink_run(sl, RUN_NORMAL); + stlink_write_reg(sl, addr, 15); /* pc register */ + stlink_run(sl, RUN_NORMAL); - while (stlink_is_core_halted(sl)) { usleep(3000000); } + while (stlink_is_core_halted(sl)) { + usleep(3000000); + } } - // this function is called by stlink_status() // do not call stlink_core_stat() directly, always use stlink_status() void stlink_core_stat(stlink_t *sl) { - switch (sl->core_stat ) { - case TARGET_RUNNING: - DLOG(" core status: running\n"); - return; - case TARGET_HALTED: - DLOG(" core status: halted\n"); - return; - case TARGET_RESET: - DLOG(" core status: reset\n"); - return; - case TARGET_DEBUG_RUNNING: - DLOG(" core status: debug running\n"); - return; - default: - DLOG(" core status: unknown\n"); - } + switch (sl->core_stat) { + case TARGET_RUNNING: + DLOG(" core status: running\n"); + return; + case TARGET_HALTED: + DLOG(" core status: halted\n"); + return; + case TARGET_RESET: + DLOG(" core status: reset\n"); + return; + case TARGET_DEBUG_RUNNING: + DLOG(" core status: debug running\n"); + return; + default: + DLOG(" core status: unknown\n"); + } } -void stlink_print_data(stlink_t * sl) { - if (sl->q_len <= 0 || sl->verbose < UDEBUG) { return; } +void stlink_print_data(stlink_t *sl) { + if (sl->q_len <= 0 || sl->verbose < UDEBUG) { + return; + } - if (sl->verbose > 2) { DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len); } + if (sl->verbose > 2) { + DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len); + } - for (int i = 0; i < sl->q_len; i++) { - if (i % 16 == 0) { - /* - if (sl->q_data_dir == Q_DATA_OUT) { - fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i); - } else { - fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i); - } - */ - } - //DLOG(" %02x", (unsigned int) sl->q_buf[i]); - fprintf(stderr, " %02x", (unsigned int) sl->q_buf[i]); + for (int i = 0; i < sl->q_len; i++) { + if (i % 16 == 0) { + /* + if (sl->q_data_dir == Q_DATA_OUT) { + fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i); + } else { + fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i); + } + */ } - //DLOG("\n\n"); - fprintf(stderr, "\n"); + // DLOG(" %02x", (unsigned int) sl->q_buf[i]); + fprintf(stderr, " %02x", (unsigned int)sl->q_buf[i]); + } + // DLOG("\n\n"); + fprintf(stderr, "\n"); } /* Memory mapped file */ typedef struct mapped_file { - uint8_t* base; - size_t len; + uint8_t *base; + size_t len; } mapped_file_t; -#define MAPPED_FILE_INITIALIZER { NULL, 0 } +#define MAPPED_FILE_INITIALIZER \ + { NULL, 0 } -static int map_file(mapped_file_t* mf, const char* path) { - int error = -1; - struct stat st; +static int map_file(mapped_file_t *mf, const char *path) { + int error = -1; + struct stat st; - const int fd = open(path, O_RDONLY | O_BINARY); + const int fd = open(path, O_RDONLY | O_BINARY); - if (fd == -1) { - fprintf(stderr, "open(%s) == -1\n", path); - return(-1); - } + if (fd == -1) { + fprintf(stderr, "open(%s) == -1\n", path); + return (-1); + } - if (fstat(fd, &st) == -1) { - fprintf(stderr, "fstat(%s) == -1\n", path); - goto on_error; - } + if (fstat(fd, &st) == -1) { + fprintf(stderr, "fstat(%s) == -1\n", path); + goto on_error; + } - if (sizeof(st.st_size) != sizeof(size_t)) { - // on 32 bit systems, check if there is an overflow - if (st.st_size > (off_t)INT32_MAX) { - fprintf(stderr, "mmap() size_t overflow for file %s\n", path); - goto on_error; - } + if (sizeof(st.st_size) != sizeof(size_t)) { + // on 32 bit systems, check if there is an overflow + if (st.st_size > (off_t)INT32_MAX) { + fprintf(stderr, "mmap() size_t overflow for file %s\n", path); + goto on_error; } + } - mf->base = (uint8_t*)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0); + mf->base = + (uint8_t *)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0); - if (mf->base == MAP_FAILED) { - fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path); - goto on_error; - } + if (mf->base == MAP_FAILED) { + fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path); + goto on_error; + } - mf->len = st.st_size; - error = 0; // success + mf->len = st.st_size; + error = 0; // success on_error: - close(fd); - return(error); + close(fd); + return (error); } -static void unmap_file(mapped_file_t * mf) { - munmap((void*)mf->base, mf->len); - mf->base = (unsigned char*)MAP_FAILED; - mf->len = 0; +static void unmap_file(mapped_file_t *mf) { + munmap((void *)mf->base, mf->len); + mf->base = (unsigned char *)MAP_FAILED; + mf->len = 0; } -/* Limit the block size to compare to 0x1800 as anything larger will stall the STLINK2 - * Maybe STLINK V1 needs smaller value! +/* Limit the block size to compare to 0x1800 as anything larger will stall the + * STLINK2 Maybe STLINK V1 needs smaller value! */ -static int check_file(stlink_t* sl, mapped_file_t* mf, stm32_addr_t addr) { - size_t off; - size_t n_cmp = sl->flash_pgsz; +static int check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) { + size_t off; + size_t n_cmp = sl->flash_pgsz; - if ( n_cmp > 0x1800) { n_cmp = 0x1800; } + if (n_cmp > 0x1800) { + n_cmp = 0x1800; + } - for (off = 0; off < mf->len; off += n_cmp) { - size_t aligned_size; + for (off = 0; off < mf->len; off += n_cmp) { + size_t aligned_size; - size_t cmp_size = n_cmp; // adjust last page size + size_t cmp_size = n_cmp; // adjust last page size - if ((off + n_cmp) > mf->len) { cmp_size = mf->len - off; } + if ((off + n_cmp) > mf->len) { + cmp_size = mf->len - off; + } - aligned_size = cmp_size; + aligned_size = cmp_size; - if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } + if (aligned_size & (4 - 1)) { + aligned_size = (cmp_size + 4) & ~(4 - 1); + } - stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size); + stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size); - if (memcmp(sl->q_buf, mf->base + off, cmp_size)) { return(-1); } + if (memcmp(sl->q_buf, mf->base + off, cmp_size)) { + return (-1); } + } - return(0); + return (0); } static void md5_calculate(mapped_file_t *mf) { - // calculate md5 checksum of given binary file - Md5Context md5Context; - MD5_HASH md5Hash; - Md5Initialise(&md5Context); - Md5Update(&md5Context, mf->base, (uint32_t)mf->len); - Md5Finalise(&md5Context, &md5Hash); - printf("md5 checksum: "); + // calculate md5 checksum of given binary file + Md5Context md5Context; + MD5_HASH md5Hash; + Md5Initialise(&md5Context); + Md5Update(&md5Context, mf->base, (uint32_t)mf->len); + Md5Finalise(&md5Context, &md5Hash); + printf("md5 checksum: "); - for (int i = 0; i < (int)sizeof(md5Hash); i++) { printf("%x", md5Hash.bytes[i]); } + for (int i = 0; i < (int)sizeof(md5Hash); i++) { + printf("%x", md5Hash.bytes[i]); + } - printf(", "); + printf(", "); } static void stlink_checksum(mapped_file_t *mp) { - /* checksum that backward compatible with official ST tools */ - uint32_t sum = 0; - uint8_t *mp_byte = (uint8_t *)mp->base; + /* checksum that backward compatible with official ST tools */ + uint32_t sum = 0; + uint8_t *mp_byte = (uint8_t *)mp->base; - for (size_t i = 0; i < mp->len; ++i) { sum += mp_byte[i]; } + for (size_t i = 0; i < mp->len; ++i) { + sum += mp_byte[i]; + } - printf("stlink checksum: 0x%08x\n", sum); + printf("stlink checksum: 0x%08x\n", sum); } static void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) { - unsigned int val; - // set stack - stlink_read_debug32(sl, addr, &val); - stlink_write_reg(sl, val, 13); - // set PC to the reset routine - stlink_read_debug32(sl, addr + 4, &val); - stlink_write_reg(sl, val, 15); - stlink_run(sl, RUN_NORMAL); -} - -int stlink_mwrite_sram(stlink_t * sl, uint8_t* data, uint32_t length, stm32_addr_t addr) { - // write the file in sram at addr - - int error = -1; - size_t off; - size_t len; - - // check addr range is inside the sram - if (addr < sl->sram_base) { - fprintf(stderr, "addr too low\n"); - goto on_error; - } else if ((addr + length) < addr) { - fprintf(stderr, "addr overruns\n"); - goto on_error; - } else if ((addr + length) > (sl->sram_base + sl->sram_size)) { - fprintf(stderr, "addr too high\n"); - goto on_error; - } else if (addr & 3) { - fprintf(stderr, "unaligned addr\n"); - goto on_error; - } - - len = length; - - if (len & 3) { len -= len & 3; } - - // do the copy by 1kB blocks - for (off = 0; off < len; off += 1024) { - size_t size = 1024; - - if ((off + size) > len) { size = len - off; } - - memcpy(sl->q_buf, data + off, size); - - if (size & 3) { size += 2; } // round size if needed - - stlink_write_mem32(sl, addr + (uint32_t)off, size); - } - - if (length > len) { - memcpy(sl->q_buf, data + len, length - len); - stlink_write_mem8(sl, addr + (uint32_t)len, length - len); - } - - - error = 0; // success - stlink_fwrite_finalize(sl, addr); + unsigned int val; + // set stack + stlink_read_debug32(sl, addr, &val); + stlink_write_reg(sl, val, 13); + // set PC to the reset routine + stlink_read_debug32(sl, addr + 4, &val); + stlink_write_reg(sl, val, 15); + stlink_run(sl, RUN_NORMAL); +} + +int stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, + stm32_addr_t addr) { + // write the file in sram at addr + + int error = -1; + size_t off; + size_t len; + + // check addr range is inside the sram + if (addr < sl->sram_base) { + fprintf(stderr, "addr too low\n"); + goto on_error; + } else if ((addr + length) < addr) { + fprintf(stderr, "addr overruns\n"); + goto on_error; + } else if ((addr + length) > (sl->sram_base + sl->sram_size)) { + fprintf(stderr, "addr too high\n"); + goto on_error; + } else if (addr & 3) { + fprintf(stderr, "unaligned addr\n"); + goto on_error; + } + + len = length; + + if (len & 3) { + len -= len & 3; + } + + // do the copy by 1kB blocks + for (off = 0; off < len; off += 1024) { + size_t size = 1024; + + if ((off + size) > len) { + size = len - off; + } + + memcpy(sl->q_buf, data + off, size); + + if (size & 3) { + size += 2; + } // round size if needed + + stlink_write_mem32(sl, addr + (uint32_t)off, size); + } + + if (length > len) { + memcpy(sl->q_buf, data + len, length - len); + stlink_write_mem8(sl, addr + (uint32_t)len, length - len); + } + + error = 0; // success + stlink_fwrite_finalize(sl, addr); on_error: - return(error); + return (error); } -int stlink_fwrite_sram(stlink_t * sl, const char* path, stm32_addr_t addr) { - // write the file in sram at addr +int stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) { + // write the file in sram at addr - int error = -1; - size_t off; - size_t len; - mapped_file_t mf = MAPPED_FILE_INITIALIZER; + int error = -1; + size_t off; + size_t len; + mapped_file_t mf = MAPPED_FILE_INITIALIZER; - if (map_file(&mf, path) == -1) { - fprintf(stderr, "map_file() == -1\n"); - return(-1); - } + if (map_file(&mf, path) == -1) { + fprintf(stderr, "map_file() == -1\n"); + return (-1); + } - printf("file %s ", path); - md5_calculate(&mf); - stlink_checksum(&mf); - - // check if addr range is inside the SRAM - if (addr < sl->sram_base) { - fprintf(stderr, "addr too low\n"); - goto on_error; - } else if ((addr + mf.len) < addr) { - fprintf(stderr, "addr overruns\n"); - goto on_error; - } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) { - fprintf(stderr, "addr too high\n"); - goto on_error; - } else if (addr & 3) { - fprintf(stderr, "unaligned addr\n"); - goto on_error; - } + printf("file %s ", path); + md5_calculate(&mf); + stlink_checksum(&mf); - len = mf.len; + // check if addr range is inside the SRAM + if (addr < sl->sram_base) { + fprintf(stderr, "addr too low\n"); + goto on_error; + } else if ((addr + mf.len) < addr) { + fprintf(stderr, "addr overruns\n"); + goto on_error; + } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) { + fprintf(stderr, "addr too high\n"); + goto on_error; + } else if (addr & 3) { + fprintf(stderr, "unaligned addr\n"); + goto on_error; + } - if (len & 3) { len -= len & 3; } + len = mf.len; - // do the copy by 1kB blocks - for (off = 0; off < len; off += 1024) { - size_t size = 1024; + if (len & 3) { + len -= len & 3; + } - if ((off + size) > len) { size = len - off; } + // do the copy by 1kB blocks + for (off = 0; off < len; off += 1024) { + size_t size = 1024; - memcpy(sl->q_buf, mf.base + off, size); + if ((off + size) > len) { + size = len - off; + } - if (size & 3) { size += 2; } // round size if needed + memcpy(sl->q_buf, mf.base + off, size); - stlink_write_mem32(sl, addr + (uint32_t)off, size); - } + if (size & 3) { + size += 2; + } // round size if needed - if (mf.len > len) { - memcpy(sl->q_buf, mf.base + len, mf.len - len); - stlink_write_mem8(sl, addr + (uint32_t)len, mf.len - len); - } + stlink_write_mem32(sl, addr + (uint32_t)off, size); + } - // check the file has been written - if (check_file(sl, &mf, addr) == -1) { - fprintf(stderr, "check_file() == -1\n"); - goto on_error; - } + if (mf.len > len) { + memcpy(sl->q_buf, mf.base + len, mf.len - len); + stlink_write_mem8(sl, addr + (uint32_t)len, mf.len - len); + } - error = 0; // success - stlink_fwrite_finalize(sl, addr); + // check the file has been written + if (check_file(sl, &mf, addr) == -1) { + fprintf(stderr, "check_file() == -1\n"); + goto on_error; + } + + error = 0; // success + stlink_fwrite_finalize(sl, addr); on_error: - unmap_file(&mf); - return(error); + unmap_file(&mf); + return (error); } -typedef bool (*save_block_fn)(void* arg, uint8_t* block, ssize_t len); +typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len); -static int stlink_read( - stlink_t* sl, stm32_addr_t addr, size_t size, save_block_fn fn, void* fn_arg) { +static int stlink_read(stlink_t *sl, stm32_addr_t addr, size_t size, + save_block_fn fn, void *fn_arg) { - int error = -1; + int error = -1; - if (size < 1) { size = sl->flash_size; } + if (size < 1) { + size = sl->flash_size; + } - if (size > sl->flash_size) { - size = sl->flash_size; - } + if (size > sl->flash_size) { + size = sl->flash_size; + } - size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; + size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; - for (size_t off = 0; off < size; off += cmp_size) { - size_t aligned_size; + for (size_t off = 0; off < size; off += cmp_size) { + size_t aligned_size; - // adjust last page size - if ((off + cmp_size) > size) { cmp_size = size - off; } + // adjust last page size + if ((off + cmp_size) > size) { + cmp_size = size - off; + } - aligned_size = cmp_size; + aligned_size = cmp_size; - if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } + if (aligned_size & (4 - 1)) { + aligned_size = (cmp_size + 4) & ~(4 - 1); + } - stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size); + stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size); - if (!fn(fn_arg, sl->q_buf, aligned_size)) { goto on_error; } + if (!fn(fn_arg, sl->q_buf, aligned_size)) { + goto on_error; } + } - error = 0; // success + error = 0; // success on_error: - return(error); + return (error); } struct stlink_fread_worker_arg { - int fd; + int fd; }; -static bool stlink_fread_worker(void* arg, uint8_t* block, ssize_t len) { - struct stlink_fread_worker_arg* the_arg = (struct stlink_fread_worker_arg*)arg; +static bool stlink_fread_worker(void *arg, uint8_t *block, ssize_t len) { + struct stlink_fread_worker_arg *the_arg = + (struct stlink_fread_worker_arg *)arg; - if (write(the_arg->fd, block, len) != len) { - fprintf(stderr, "write() != aligned_size\n"); - return(false); - } else { - return(true); - } + if (write(the_arg->fd, block, len) != len) { + fprintf(stderr, "write() != aligned_size\n"); + return (false); + } else { + return (true); + } } struct stlink_fread_ihex_worker_arg { - FILE* file; - uint32_t addr; - uint32_t lba; - uint8_t buf[16]; - uint8_t buf_pos; + FILE *file; + uint32_t addr; + uint32_t lba; + uint8_t buf[16]; + uint8_t buf_pos; }; -static bool stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg* the_arg) { - uint32_t addr = the_arg->addr; - uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) + (uint8_t)((addr & 0x00FF0000) >> 16); +static bool +stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg) { + uint32_t addr = the_arg->addr; + uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) + + (uint8_t)((addr & 0x00FF0000) >> 16); - if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n", (addr & 0xFFFF0000) >> 16, - (uint8_t)(0x100 - sum))) { - return(false); - } + if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n", + (addr & 0xFFFF0000) >> 16, (uint8_t)(0x100 - sum))) { + return (false); + } - the_arg->lba = (addr & 0xFFFF0000); - return(true); + the_arg->lba = (addr & 0xFFFF0000); + return (true); } -static bool stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg* the_arg) { - uint8_t count = the_arg->buf_pos; +static bool +stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg) { + uint8_t count = the_arg->buf_pos; - if (count == 0) { return(true); } + if (count == 0) { + return (true); + } - uint32_t addr = the_arg->addr; + uint32_t addr = the_arg->addr; - if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed - if (!stlink_fread_ihex_newsegment(the_arg)) { - return(false); - } + if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed + if (!stlink_fread_ihex_newsegment(the_arg)) { + return (false); } + } - uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) + (uint8_t)(addr & 0x000000FF); + uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) + + (uint8_t)(addr & 0x000000FF); - if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) { - return(false); - } + if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) { + return (false); + } - for (uint8_t i = 0; i < count; ++i) { - uint8_t b = the_arg->buf[i]; - sum += b; + for (uint8_t i = 0; i < count; ++i) { + uint8_t b = the_arg->buf[i]; + sum += b; - if (2 != fprintf(the_arg->file, "%02X", b)) { - return(false); - } + if (2 != fprintf(the_arg->file, "%02X", b)) { + return (false); } + } - if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) { - return(false); - } + if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) { + return (false); + } - the_arg->addr += count; - the_arg->buf_pos = 0; + the_arg->addr += count; + the_arg->buf_pos = 0; - return(true); + return (true); } -static bool stlink_fread_ihex_init( - struct stlink_fread_ihex_worker_arg* the_arg, int fd, stm32_addr_t addr) { - the_arg->file = fdopen(fd, "w"); - the_arg->addr = addr; - the_arg->lba = 0; - the_arg->buf_pos = 0; +static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg, + int fd, stm32_addr_t addr) { + the_arg->file = fdopen(fd, "w"); + the_arg->addr = addr; + the_arg->lba = 0; + the_arg->buf_pos = 0; - return (the_arg->file != NULL); + return (the_arg->file != NULL); } -static bool stlink_fread_ihex_worker(void* arg, uint8_t* block, ssize_t len) { - struct stlink_fread_ihex_worker_arg* the_arg = (struct stlink_fread_ihex_worker_arg*)arg; - - for (ssize_t i = 0; i < len; ++i) { - if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full - if (!stlink_fread_ihex_writeline(the_arg)) { return(false); } - } +static bool stlink_fread_ihex_worker(void *arg, uint8_t *block, ssize_t len) { + struct stlink_fread_ihex_worker_arg *the_arg = + (struct stlink_fread_ihex_worker_arg *)arg; - the_arg->buf[the_arg->buf_pos++] = block[i]; + for (ssize_t i = 0; i < len; ++i) { + if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full + if (!stlink_fread_ihex_writeline(the_arg)) { + return (false); + } } - return(true); + the_arg->buf[the_arg->buf_pos++] = block[i]; + } + + return (true); } -static bool stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg* the_arg) { - if (!stlink_fread_ihex_writeline(the_arg)) { return(false); } +static bool +stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *the_arg) { + if (!stlink_fread_ihex_writeline(the_arg)) { + return (false); + } - // FIXME: do we need the Start Linear Address? + // FIXME: do we need the Start Linear Address? - if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF - return(false); - } + if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF + return (false); + } - return (0 == fclose(the_arg->file)); + return (0 == fclose(the_arg->file)); } -int stlink_fread(stlink_t* sl, const char* path, bool is_ihex, stm32_addr_t addr, size_t size) { - // read size bytes from addr to file - ILOG("read from address %#010x size %u\n", addr, (unsigned)size); +int stlink_fread(stlink_t *sl, const char *path, bool is_ihex, + stm32_addr_t addr, size_t size) { + // read size bytes from addr to file + ILOG("read from address %#010x size %u\n", addr, (unsigned)size); - int error; - int fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700); + int error; + int fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700); - if (fd == -1) { - fprintf(stderr, "open(%s) == -1\n", path); - return(-1); - } + if (fd == -1) { + fprintf(stderr, "open(%s) == -1\n", path); + return (-1); + } - if (is_ihex) { - struct stlink_fread_ihex_worker_arg arg; + if (is_ihex) { + struct stlink_fread_ihex_worker_arg arg; - if (stlink_fread_ihex_init(&arg, fd, addr)) { - error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg); + if (stlink_fread_ihex_init(&arg, fd, addr)) { + error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg); - if (!stlink_fread_ihex_finalize(&arg)) { error = -1; } - } else { - error = -1; - } + if (!stlink_fread_ihex_finalize(&arg)) { + error = -1; + } } else { - struct stlink_fread_worker_arg arg = { fd }; - error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg); + error = -1; } + } else { + struct stlink_fread_worker_arg arg = {fd}; + error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg); + } - close(fd); - return(error); + close(fd); + return (error); } -int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size) { - // write the buffer right after the loader - size_t chunk = size & ~0x3; - size_t rem = size & 0x3; +int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf, + size_t size) { + // write the buffer right after the loader + size_t chunk = size & ~0x3; + size_t rem = size & 0x3; - if (chunk) { - memcpy(sl->q_buf, buf, chunk); - stlink_write_mem32(sl, fl->buf_addr, chunk); - } + if (chunk) { + memcpy(sl->q_buf, buf, chunk); + stlink_write_mem32(sl, fl->buf_addr, chunk); + } - if (rem) { - memcpy(sl->q_buf, buf + chunk, rem); - stlink_write_mem8(sl, (fl->buf_addr) + (uint32_t)chunk, rem); - } + if (rem) { + memcpy(sl->q_buf, buf + chunk, rem); + stlink_write_mem8(sl, (fl->buf_addr) + (uint32_t)chunk, rem); + } - return(0); + return (0); } uint32_t calculate_F4_sectornum(uint32_t flashaddr) { - uint32_t offset = 0; - flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address - - if (flashaddr >= 0x100000) { - offset = 12; - flashaddr -= 0x100000; - } - - if (flashaddr < 0x4000) { - return (offset + 0); - } else if (flashaddr < 0x8000) { - return(offset + 1); - } else if (flashaddr < 0xc000) { - return(offset + 2); - } else if (flashaddr < 0x10000) { - return(offset + 3); - } else if (flashaddr < 0x20000) { - return(offset + 4); - } else { - return(offset + (flashaddr / 0x20000) + 4); - } - + uint32_t offset = 0; + flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address + + if (flashaddr >= 0x100000) { + offset = 12; + flashaddr -= 0x100000; + } + + if (flashaddr < 0x4000) { + return (offset + 0); + } else if (flashaddr < 0x8000) { + return (offset + 1); + } else if (flashaddr < 0xc000) { + return (offset + 2); + } else if (flashaddr < 0x10000) { + return (offset + 3); + } else if (flashaddr < 0x20000) { + return (offset + 4); + } else { + return (offset + (flashaddr / 0x20000) + 4); + } } uint32_t calculate_F7_sectornum(uint32_t flashaddr) { - flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address - - if (flashaddr < 0x20000) { - return(flashaddr / 0x8000); - } else if (flashaddr < 0x40000) { - return(4); - } else { - return((flashaddr / 0x40000) + 4); - } + flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address + if (flashaddr < 0x20000) { + return (flashaddr / 0x8000); + } else if (flashaddr < 0x40000) { + return (4); + } else { + return ((flashaddr / 0x40000) + 4); + } } -uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr, unsigned bank) { - flashaddr &= ~((bank==BANK_1)?STM32_FLASH_BASE:STM32_H7_FLASH_BANK2_BASE); // sector holding the flash address - return(flashaddr / sl->flash_pgsz); +uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr, + unsigned bank) { + flashaddr &= + ~((bank == BANK_1) + ? STM32_FLASH_BASE + : STM32_H7_FLASH_BANK2_BASE); // sector holding the flash address + return (flashaddr / sl->flash_pgsz); } // returns BKER:PNB for the given page address uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) { - uint32_t bker = 0; - uint32_t flashopt; - stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt); - flashaddr -= STM32_FLASH_BASE; - - if (sl->chip_id == STLINK_CHIPID_STM32_L4 || - sl->chip_id == STLINK_CHIPID_STM32_L496X || - sl->chip_id == STLINK_CHIPID_STM32_L4RX) { - // this chip use dual banked flash - if (flashopt & (uint32_t)(1lu << STM32L4_FLASH_OPTR_DUALBANK)) { - uint32_t banksize = (uint32_t)sl->flash_size / 2; - - if (flashaddr >= banksize) { - flashaddr -= banksize; - bker = 0x100; - } - } + uint32_t bker = 0; + uint32_t flashopt; + stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt); + flashaddr -= STM32_FLASH_BASE; + + if (sl->chip_id == STLINK_CHIPID_STM32_L4 || + sl->chip_id == STLINK_CHIPID_STM32_L496X || + sl->chip_id == STLINK_CHIPID_STM32_L4RX) { + // this chip use dual banked flash + if (flashopt & (uint32_t)(1lu << STM32L4_FLASH_OPTR_DUALBANK)) { + uint32_t banksize = (uint32_t)sl->flash_size / 2; + + if (flashaddr >= banksize) { + flashaddr -= banksize; + bker = 0x100; + } } + } - // For 1MB chips without the dual-bank option set, the page address will overflow - // into the BKER bit, which gives us the correct bank:page value. - return(bker | flashaddr / (uint32_t)sl->flash_pgsz); + // For 1MB chips without the dual-bank option set, the page address will + // overflow into the BKER bit, which gives us the correct bank:page value. + return (bker | flashaddr / (uint32_t)sl->flash_pgsz); } uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) { - if ((sl->chip_id == STLINK_CHIPID_STM32_F2) || - (sl->chip_id == STLINK_CHIPID_STM32_F4) || - (sl->chip_id == STLINK_CHIPID_STM32_F4_DE) || - (sl->chip_id == STLINK_CHIPID_STM32_F4_LP) || - (sl->chip_id == STLINK_CHIPID_STM32_F4_HD) || - (sl->chip_id == STLINK_CHIPID_STM32_F411RE) || - (sl->chip_id == STLINK_CHIPID_STM32_F446) || - (sl->chip_id == STLINK_CHIPID_STM32_F4_DSI) || - (sl->chip_id == STLINK_CHIPID_STM32_F72XXX) || - (sl->chip_id == STLINK_CHIPID_STM32_F412)) { - uint32_t sector = calculate_F4_sectornum(flashaddr); - - if (sector >= 12) { sector -= 12; } - - if (sector < 4) { - sl->flash_pgsz = 0x4000; - } else if (sector < 5) { - sl->flash_pgsz = 0x10000; - } else { - sl->flash_pgsz = 0x20000; - } - } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 || - sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) { - uint32_t sector = calculate_F7_sectornum(flashaddr); + if ((sl->chip_id == STLINK_CHIPID_STM32_F2) || + (sl->chip_id == STLINK_CHIPID_STM32_F4) || + (sl->chip_id == STLINK_CHIPID_STM32_F4_DE) || + (sl->chip_id == STLINK_CHIPID_STM32_F4_LP) || + (sl->chip_id == STLINK_CHIPID_STM32_F4_HD) || + (sl->chip_id == STLINK_CHIPID_STM32_F411RE) || + (sl->chip_id == STLINK_CHIPID_STM32_F446) || + (sl->chip_id == STLINK_CHIPID_STM32_F4_DSI) || + (sl->chip_id == STLINK_CHIPID_STM32_F72XXX) || + (sl->chip_id == STLINK_CHIPID_STM32_F412)) { + uint32_t sector = calculate_F4_sectornum(flashaddr); + + if (sector >= 12) { + sector -= 12; + } + + if (sector < 4) { + sl->flash_pgsz = 0x4000; + } else if (sector < 5) { + sl->flash_pgsz = 0x10000; + } else { + sl->flash_pgsz = 0x20000; + } + } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 || + sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) { + uint32_t sector = calculate_F7_sectornum(flashaddr); - if (sector < 4) { - sl->flash_pgsz = 0x8000; - } else if (sector < 5) { - sl->flash_pgsz = 0x20000; - } else { - sl->flash_pgsz = 0x40000; - } + if (sector < 4) { + sl->flash_pgsz = 0x8000; + } else if (sector < 5) { + sl->flash_pgsz = 0x20000; + } else { + sl->flash_pgsz = 0x40000; } + } - return((uint32_t)sl->flash_pgsz); + return ((uint32_t)sl->flash_pgsz); } /** - * Erase a page of flash, assumes sl is fully populated with things like chip/core ids + * Erase a page of flash, assumes sl is fully populated with things like + * chip/core ids * @param sl stlink context * @param flashaddr an address in the flash page to erase * @return 0 on success -ve on failure */ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) { - // wait for ongoing op to finish - wait_flash_busy(sl); - // clear flash IO errors - clear_flash_error(sl); + // wait for ongoing op to finish + wait_flash_busy(sl); + // clear flash IO errors + clear_flash_error(sl); + + if (sl->flash_type == STLINK_FLASH_TYPE_F4 || + sl->flash_type == STLINK_FLASH_TYPE_F7 || + sl->flash_type == STLINK_FLASH_TYPE_L4) { + // unlock if locked + unlock_flash_if(sl); + + // select the page to erase + if ((sl->chip_id == STLINK_CHIPID_STM32_L4) || + (sl->chip_id == STLINK_CHIPID_STM32_L43X) || + (sl->chip_id == STLINK_CHIPID_STM32_L46X) || + (sl->chip_id == STLINK_CHIPID_STM32_L496X) || + (sl->chip_id == STLINK_CHIPID_STM32_L4RX)) { + // calculate the actual bank+page from the address + uint32_t page = calculate_L4_page(sl, flashaddr); + + fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page, + stlink_calculate_pagesize(sl, flashaddr)); + + write_flash_cr_bker_pnb(sl, page); + } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 || + sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) { + // calculate the actual page from the address + uint32_t sector = calculate_F7_sectornum(flashaddr); - if (sl->flash_type == STLINK_FLASH_TYPE_F4 || - sl->flash_type == STLINK_FLASH_TYPE_F7 || - sl->flash_type == STLINK_FLASH_TYPE_L4) { - // unlock if locked - unlock_flash_if(sl); - - // select the page to erase - if ((sl->chip_id == STLINK_CHIPID_STM32_L4) || - (sl->chip_id == STLINK_CHIPID_STM32_L43X) || - (sl->chip_id == STLINK_CHIPID_STM32_L46X) || - (sl->chip_id == STLINK_CHIPID_STM32_L496X) || - (sl->chip_id == STLINK_CHIPID_STM32_L4RX)) { - // calculate the actual bank+page from the address - uint32_t page = calculate_L4_page(sl, flashaddr); - - fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", - page, stlink_calculate_pagesize(sl, flashaddr)); - - write_flash_cr_bker_pnb(sl, page); - } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 || - sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) { - // calculate the actual page from the address - uint32_t sector = calculate_F7_sectornum(flashaddr); - - fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", - sector, stlink_calculate_pagesize(sl, flashaddr)); - write_flash_cr_snb(sl, sector, BANK_1); - } else { - // calculate the actual page from the address - uint32_t sector = calculate_F4_sectornum(flashaddr); + fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector, + stlink_calculate_pagesize(sl, flashaddr)); + write_flash_cr_snb(sl, sector, BANK_1); + } else { + // calculate the actual page from the address + uint32_t sector = calculate_F4_sectornum(flashaddr); - fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", - sector, stlink_calculate_pagesize(sl, flashaddr)); + fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector, + stlink_calculate_pagesize(sl, flashaddr)); - // the SNB values for flash sectors in the second bank do not directly - // follow the values for the first bank on 2mb devices... - if (sector >= 12) { sector += 4; } + // the SNB values for flash sectors in the second bank do not directly + // follow the values for the first bank on 2mb devices... + if (sector >= 12) { + sector += 4; + } - write_flash_cr_snb(sl, sector, BANK_1); - } + write_flash_cr_snb(sl, sector, BANK_1); + } - set_flash_cr_strt(sl, BANK_1); // start erase operation - wait_flash_busy(sl); // wait for completion - lock_flash(sl); // TODO: fails to program if this is in + set_flash_cr_strt(sl, BANK_1); // start erase operation + wait_flash_busy(sl); // wait for completion + lock_flash(sl); // TODO: fails to program if this is in #if DEBUG_FLASH - fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1)); + fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1)); #endif - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - uint32_t val; - uint32_t flash_regs_base = get_stm32l0_flash_base(sl); + uint32_t val; + uint32_t flash_regs_base = get_stm32l0_flash_base(sl); - // check if the locks are set - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + // check if the locks are set + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - if ((val & (1 << 0)) || (val & (1 << 1))) { - // disable pecr protection - stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1); - stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2); + if ((val & (1 << 0)) || (val & (1 << 1))) { + // disable pecr protection + stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, + FLASH_L0_PEKEY1); + stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, + FLASH_L0_PEKEY2); - // check pecr.pelock is cleared - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + // check pecr.pelock is cleared + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - if (val & (1 << 0)) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return(-1); - } + if (val & (1 << 0)) { + WLOG("pecr.pelock not clear (%#x)\n", val); + return (-1); + } - // unlock program memory - stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1); - stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2); + // unlock program memory + stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, + FLASH_L0_PRGKEY1); + stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, + FLASH_L0_PRGKEY2); - // check pecr.prglock is cleared - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + // check pecr.prglock is cleared + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - if (val & (1 << 1)) { - WLOG("pecr.prglock not clear (%#x)\n", val); - return(-1); - } - } + if (val & (1 << 1)) { + WLOG("pecr.prglock not clear (%#x)\n", val); + return (-1); + } + } - // set pecr.{erase,prog} - val |= (1 << 9) | (1 << 3); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - - // write 0 to the first word of the page to be erased - stlink_write_debug32(sl, flashaddr, 0); - - /* MP: It is better to wait for clearing the busy bit after issuing page - * erase command, even though PM0062 recommends to wait before it. - * Test shows that a few iterations is performed in the following loop - * before busy bit is cleared. - */ - wait_flash_busy(sl); - - // reset lock bits - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val |= (1 << 0) | (1 << 1) | (1 << 2); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || - sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - uint32_t val; - unlock_flash_if(sl); - set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit - - // set the page to erase - if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - - // sec 3.10.5 - PNB[7:0] is offset by 3. - val &= ~(0xFF << 3); // Clear previously set page number (if any) - val |= ((flash_page & 0xFF) << 3); - - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); - stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); - // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. - val &= ~(0x3F << 3); - val |= ((flash_page & 0x3F) << 3) | (1 << FLASH_CR_PER); - stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G4) { - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); - stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); - // sec 3.7.5 - PNB[6:0] is offset by 3. PER is 0x2. - val &= ~(0x7F << 3); - val |= ((flash_page & 0x7F) << 3) | (1 << FLASH_CR_PER); - stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); - } + // set pecr.{erase,prog} + val |= (1 << 9) | (1 << 3); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit - wait_flash_busy(sl); // wait for the 'busy' bit to clear - clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit - lock_flash(sl); - } else if (sl->flash_type == STLINK_FLASH_TYPE_F0 || - sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { - unsigned bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE)?BANK_1:BANK_2; - unlock_flash_if(sl); - clear_flash_cr_pg(sl, bank); // clear the pg bit - set_flash_cr_per(sl, bank); // set the page erase bit - write_flash_ar(sl, flashaddr, bank); // select the page to erase - set_flash_cr_strt(sl, bank); // start erase operation, reset by hw with busy bit - wait_flash_busy(sl); - clear_flash_cr_per(sl, bank); // clear the page erase bit - lock_flash(sl); - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - unsigned bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE)?BANK_1:BANK_2; - unlock_flash_if(sl); // unlock if locked - uint32_t sector = calculate_H7_sectornum(sl, flashaddr, bank);// calculate the actual page from the address - write_flash_cr_snb(sl, sector, bank); // select the page to erase - set_flash_cr_strt(sl, bank); // start erase operation - wait_flash_busy(sl); // wait for completion - lock_flash(sl); - } else { - WLOG("unknown coreid %x, page erase failed\n", sl->core_id); - return(-1); - } + // write 0 to the first word of the page to be erased + stlink_write_debug32(sl, flashaddr, 0); + + /* MP: It is better to wait for clearing the busy bit after issuing page + * erase command, even though PM0062 recommends to wait before it. + * Test shows that a few iterations is performed in the following loop + * before busy bit is cleared. + */ + wait_flash_busy(sl); + + // reset lock bits + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val |= (1 << 0) | (1 << 1) | (1 << 2); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + uint32_t val; + unlock_flash_if(sl); + set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit + + // set the page to erase + if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + uint32_t flash_page = + ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + + // sec 3.10.5 - PNB[7:0] is offset by 3. + val &= ~(0xFF << 3); // Clear previously set page number (if any) + val |= ((flash_page & 0xFF) << 3); + + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + uint32_t flash_page = + ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. + val &= ~(0x3F << 3); + val |= ((flash_page & 0x3F) << 3) | (1 << FLASH_CR_PER); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G4) { + uint32_t flash_page = + ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz)); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + // sec 3.7.5 - PNB[6:0] is offset by 3. PER is 0x2. + val &= ~(0x7F << 3); + val |= ((flash_page & 0x7F) << 3) | (1 << FLASH_CR_PER); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); + } + + set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit + wait_flash_busy(sl); // wait for the 'busy' bit to clear + clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit + lock_flash(sl); + } else if (sl->flash_type == STLINK_FLASH_TYPE_F0 || + sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { + unsigned bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; + unlock_flash_if(sl); + clear_flash_cr_pg(sl, bank); // clear the pg bit + set_flash_cr_per(sl, bank); // set the page erase bit + write_flash_ar(sl, flashaddr, bank); // select the page to erase + set_flash_cr_strt(sl, + bank); // start erase operation, reset by hw with busy bit + wait_flash_busy(sl); + clear_flash_cr_per(sl, bank); // clear the page erase bit + lock_flash(sl); + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + unsigned bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; + unlock_flash_if(sl); // unlock if locked + uint32_t sector = calculate_H7_sectornum( + sl, flashaddr, bank); // calculate the actual page from the address + write_flash_cr_snb(sl, sector, bank); // select the page to erase + set_flash_cr_strt(sl, bank); // start erase operation + wait_flash_busy(sl); // wait for completion + lock_flash(sl); + } else { + WLOG("unknown coreid %x, page erase failed\n", sl->core_id); + return (-1); + } - return check_flash_error(sl); + return check_flash_error(sl); } int stlink_erase_flash_mass(stlink_t *sl) { - int err = 0; + int err = 0; - // TODO: User MER bit to mass-erase WB series. - if (sl->flash_type == STLINK_FLASH_TYPE_L0 || - sl->flash_type == STLINK_FLASH_TYPE_WB) { - // erase each page - int i = 0, num_pages = (int)(sl->flash_size / sl->flash_pgsz); + // TODO: User MER bit to mass-erase WB series. + if (sl->flash_type == STLINK_FLASH_TYPE_L0 || + sl->flash_type == STLINK_FLASH_TYPE_WB) { + // erase each page + int i = 0, num_pages = (int)(sl->flash_size / sl->flash_pgsz); - for (i = 0; i < num_pages; i++) { - // addr must be an addr inside the page - stm32_addr_t addr = (stm32_addr_t)sl->flash_base + i * (stm32_addr_t)sl->flash_pgsz; + for (i = 0; i < num_pages; i++) { + // addr must be an addr inside the page + stm32_addr_t addr = + (stm32_addr_t)sl->flash_base + i * (stm32_addr_t)sl->flash_pgsz; - if (stlink_erase_flash_page(sl, addr)) { - WLOG("Failed to erase_flash_page(%#x) == -1\n", addr); - return(-1); - } + if (stlink_erase_flash_page(sl, addr)) { + WLOG("Failed to erase_flash_page(%#x) == -1\n", addr); + return (-1); + } - fprintf(stdout, "-> Flash page at %5d/%5d erased\n", i, num_pages); - fflush(stdout); - } + fprintf(stdout, "-> Flash page at %5d/%5d erased\n", i, num_pages); + fflush(stdout); + } - fprintf(stdout, "\n"); - } else { - wait_flash_busy(sl); - clear_flash_error(sl); - unlock_flash_if(sl); - - if (sl->flash_type == STLINK_FLASH_TYPE_H7 && sl->chip_id != STLINK_CHIPID_STM32_H7AX) { - // set parallelism - write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1); - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2); - } - } + fprintf(stdout, "\n"); + } else { + wait_flash_busy(sl); + clear_flash_error(sl); + unlock_flash_if(sl); - set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit - set_flash_cr_strt(sl, BANK_1); // start erase operation, reset by hw with busy bit + if (sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_id != STLINK_CHIPID_STM32_H7AX) { + // set parallelism + write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1); + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2); + } + } - if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || - (sl->flash_type == STLINK_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { - set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2 - set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2 - } + set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit + set_flash_cr_strt( + sl, BANK_1); // start erase operation, reset by hw with busy bit - wait_flash_busy_progress(sl); - lock_flash(sl); + if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || + (sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { + set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2 + set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2 + } - // reset the mass erase bit - set_flash_cr_mer(sl, 0, BANK_1); - if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || - (sl->flash_type == STLINK_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { - set_flash_cr_mer(sl, 0, BANK_2); - } + wait_flash_busy_progress(sl); + lock_flash(sl); - err = check_flash_error(sl); + // reset the mass erase bit + set_flash_cr_mer(sl, 0, BANK_1); + if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL || + (sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { + set_flash_cr_mer(sl, 0, BANK_2); } - return(err); + err = check_flash_error(sl); + } + + return (err); } -int stlink_fcheck_flash(stlink_t *sl, const char* path, stm32_addr_t addr) { - // check the contents of path are at addr +int stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { + // check the contents of path are at addr - int res; - mapped_file_t mf = MAPPED_FILE_INITIALIZER; + int res; + mapped_file_t mf = MAPPED_FILE_INITIALIZER; - if (map_file(&mf, path) == -1) { return(-1); } + if (map_file(&mf, path) == -1) { + return (-1); + } - res = check_file(sl, &mf, addr); - unmap_file(&mf); - return(res); + res = check_file(sl, &mf, addr); + unmap_file(&mf); + return (res); } /** @@ -2946,696 +3047,741 @@ int stlink_fcheck_flash(stlink_t *sl, const char* path, stm32_addr_t addr) { * @param length how much * @return 0 for success, -ve for failure */ -int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, unsigned length) { - size_t off; - size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; - ILOG("Starting verification of write complete\n"); +int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, + unsigned length) { + size_t off; + size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; + ILOG("Starting verification of write complete\n"); - for (off = 0; off < length; off += cmp_size) { - size_t aligned_size; + for (off = 0; off < length; off += cmp_size) { + size_t aligned_size; - // adjust last page size - if ((off + cmp_size) > length) { cmp_size = length - off; } - - aligned_size = cmp_size; - - if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } - - stlink_read_mem32(sl, address + (uint32_t)off, aligned_size); - - if (memcmp(sl->q_buf, data + off, cmp_size)) { - ELOG("Verification of flash failed at offset: %u\n", (unsigned int)off); - return(-1); - } + // adjust last page size + if ((off + cmp_size) > length) { + cmp_size = length - off; } - ILOG("Flash written and verified! jolly good!\n"); - return(0); + aligned_size = cmp_size; -} - -int stm32l1_write_half_pages( - stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint32_t pagesize) { - unsigned int count; - unsigned int num_half_pages = len / pagesize; - uint32_t val; - uint32_t flash_regs_base = get_stm32l0_flash_base(sl); - flash_loader_t fl; - - ILOG("Starting Half page flash write for STM32L core id\n"); - - /* Flash loader initialisation */ - if (stlink_flash_loader_init(sl, &fl) == -1) { - WLOG("stlink_flash_loader_init() == -1\n"); - return(-1); + if (aligned_size & (4 - 1)) { + aligned_size = (cmp_size + 4) & ~(4 - 1); } - // unlock already done - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val |= (1 << FLASH_L1_FPRG); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - - val |= (1 << FLASH_L1_PROG); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - - wait_flash_busy(sl); - - for (count = 0; count < num_half_pages; count++) { - if (stlink_flash_loader_run( - sl, &fl, addr + count * pagesize, base + count * pagesize, pagesize) == -1) { - WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", addr + count * pagesize); - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG)); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - return(-1); - } + stlink_read_mem32(sl, address + (uint32_t)off, aligned_size); - // wait for sr.busy to be cleared - if (sl->verbose >= 1) { - // show progress; writing procedure is slow and previous errors are misleading - fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages); - fflush(stdout); - } - - wait_flash_busy(sl); + if (memcmp(sl->q_buf, data + off, cmp_size)) { + ELOG("Verification of flash failed at offset: %u\n", (unsigned int)off); + return (-1); } + } - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val &= ~(1 << FLASH_L1_PROG); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val &= ~(1 << FLASH_L1_FPRG); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - return(0); + ILOG("Flash written and verified! jolly good!\n"); + return (0); } -int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { - - // According to DDI0419C, Table C1-7 firstly force halt - stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | - STLINK_REG_DHCSR_C_DEBUGEN | - STLINK_REG_DHCSR_C_HALT); - // and only then disable interrupts - stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | - STLINK_REG_DHCSR_C_DEBUGEN | - STLINK_REG_DHCSR_C_HALT | - STLINK_REG_DHCSR_C_MASKINTS); - - // disable DMA - set_dma_state(sl, fl, 0); - - // wait for ongoing op to finish - wait_flash_busy(sl); - // Clear errors - clear_flash_error(sl); - - if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || - (sl->flash_type == STLINK_FLASH_TYPE_F7) || - (sl->flash_type == STLINK_FLASH_TYPE_L4)) { - ILOG("Starting Flash write for F2/F4/F7/L4\n"); - - // Flash loader initialisation - if (stlink_flash_loader_init(sl, fl) == -1) { - ELOG("stlink_flash_loader_init() == -1\n"); - return(-1); - } - - unlock_flash_if(sl); // first unlock the cr - - int voltage; - if (sl->version.stlink_v == 1) { - WLOG("STLINK V1 cannot read voltage, use default voltage 3.2V\n"); - voltage = 3200; - } else { - voltage = stlink_target_voltage(sl); - } - - if (voltage == -1) { - ELOG("Failed to read Target voltage\n"); - return(-1); - } - - if (sl->flash_type == STLINK_FLASH_TYPE_L4) { - // L4 does not have a byte-write mode - if (voltage < 1710) { - ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage); - return(-1); - } - } else { - if (voltage > 2700) { - ILOG("enabling 32-bit flash writes\n"); - write_flash_cr_psiz(sl, 2, BANK_1); - } else { - ILOG("Target voltage (%d mV) too low for 32-bit flash, " - "using 8-bit flash writes\n", voltage); - write_flash_cr_psiz(sl, 0, BANK_1); - } - } - - // set programming mode - set_flash_cr_pg(sl, BANK_1); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || - sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - ILOG("Starting Flash write for WB/G0/G4\n"); - - unlock_flash_if(sl); // unlock flash if necessary - set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - ILOG("Starting Flash write for L0\n"); - - uint32_t val; - uint32_t flash_regs_base; - if (sl->chip_id == STLINK_CHIPID_STM32_L0 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || - sl->chip_id == STLINK_CHIPID_STM32_L011) { - flash_regs_base = STM32L0_FLASH_REGS_ADDR; - } else { - flash_regs_base = STM32L_FLASH_REGS_ADDR; - } - - // disable pecr protection - stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1); - stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2); - - // check pecr.pelock is cleared - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - if (val & (1 << 0)) { - ELOG("pecr.pelock not clear\n"); - return(-1); - } - - // unlock program memory - stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1); - stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2); +int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base, + uint32_t len, uint32_t pagesize) { + unsigned int count; + unsigned int num_half_pages = len / pagesize; + uint32_t val; + uint32_t flash_regs_base = get_stm32l0_flash_base(sl); + flash_loader_t fl; - // check pecr.prglock is cleared - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - if (val & (1 << 1)) { - ELOG("pecr.prglock not clear\n"); - return(-1); - } - } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { - ILOG("Starting Flash write for VL/F0/F3/F1_XL\n"); - - // flash loader initialisation - if (stlink_flash_loader_init(sl, fl) == -1) { - ELOG("stlink_flash_loader_init() == -1\n"); - return(-1); - } - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - ILOG("Starting Flash write for H7\n"); + ILOG("Starting Half page flash write for STM32L core id\n"); - unlock_flash_if(sl); // unlock the cr - set_flash_cr_pg(sl, BANK_1); // set programming mode - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - set_flash_cr_pg(sl, BANK_2); - } - if (sl->chip_id != STLINK_CHIPID_STM32_H7AX) { - // set parallelism - write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1); - if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2); - } - } - } else { - ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id); - return(-1); - } + /* Flash loader initialisation */ + if (stlink_flash_loader_init(sl, &fl) == -1) { + WLOG("stlink_flash_loader_init() == -1\n"); + return (-1); + } - return(0); -} - -int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, - uint8_t* base, uint32_t len) { - size_t off; - if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || - (sl->flash_type == STLINK_FLASH_TYPE_F7) || - (sl->flash_type == STLINK_FLASH_TYPE_L4)) { - size_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000; - for (off = 0; off < len;) { - size_t size = len - off > buf_size ? buf_size : len - off; - if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off, size) == -1) { - ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (unsigned)(addr + off)); - check_flash_error(sl); - return(-1); - } + // unlock already done + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val |= (1 << FLASH_L1_FPRG); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - off += size; - } - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || - sl->flash_type == STLINK_FLASH_TYPE_G0 || - sl->flash_type == STLINK_FLASH_TYPE_G4) { - DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz)); - for (off = 0; off < len; off += sizeof(uint32_t)) { - uint32_t data; - - if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { - fprintf(stdout, "\r%3u/%3u pages written", - (unsigned int)(off / sl->flash_pgsz), - (unsigned int)(len / sl->flash_pgsz)); - fflush(stdout); - } - - write_uint32((unsigned char*)&data, *(uint32_t*)(base + off)); - stlink_write_debug32(sl, addr + (uint32_t)off, data); - wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear - } - fprintf(stdout, "\n"); - - // flash writes happen as 2 words at a time - if ((off / sizeof(uint32_t)) % 2 != 0) { - stlink_write_debug32(sl, addr + (uint32_t)off, 0); // write a single word of zeros - wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear - } - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - uint32_t val; - uint32_t flash_regs_base; - uint32_t pagesize; - - if (sl->chip_id == STLINK_CHIPID_STM32_L0 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || - sl->chip_id == STLINK_CHIPID_STM32_L011) { - flash_regs_base = STM32L0_FLASH_REGS_ADDR; - pagesize = L0_WRITE_BLOCK_SIZE; - } else { - flash_regs_base = STM32L_FLASH_REGS_ADDR; - pagesize = L1_WRITE_BLOCK_SIZE; - } + val |= (1 << FLASH_L1_PROG); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - off = 0; + wait_flash_busy(sl); - if (len > pagesize) { - if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) { - // this may happen on a blank device! - WLOG("\nwrite_half_pages failed == -1\n"); - } else { - off = (len / pagesize) * pagesize; - } - } + for (count = 0; count < num_half_pages; count++) { + if (stlink_flash_loader_run(sl, &fl, addr + count * pagesize, + base + count * pagesize, pagesize) == -1) { + WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", + addr + count * pagesize); + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG)); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + return (-1); + } - // write remaining word in program memory - for ( ; off < len; off += sizeof(uint32_t)) { - uint32_t data; + // wait for sr.busy to be cleared + if (sl->verbose >= 1) { + // show progress; writing procedure is slow and previous errors are + // misleading + fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages); + fflush(stdout); + } - if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { - fprintf(stdout, "\r%3u/%3u pages written", - (unsigned int)(off / sl->flash_pgsz), - (unsigned int)(len / sl->flash_pgsz)); - fflush(stdout); - } + wait_flash_busy(sl); + } - write_uint32((unsigned char*)&data, *(uint32_t*)(base + off)); - stlink_write_debug32(sl, addr + (uint32_t)off, data); + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val &= ~(1 << FLASH_L1_PROG); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val &= ~(1 << FLASH_L1_FPRG); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + return (0); +} - // wait for sr.busy to be cleared - do { - stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val); - } while ((val & (1 << 0)) != 0); +int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { - // TODO: check redo write operation - } - fprintf(stdout, "\n"); - } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || - (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { - int write_block_count = 0; - for (off = 0; off < len; off += sl->flash_pgsz) { - // adjust last write size - size_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off; - - // unlock and set programming mode - unlock_flash_if(sl); - - DLOG("Finished unlocking flash, running loader!\n"); - - if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off, size) == -1) { - ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (unsigned)(addr + off)); - check_flash_error(sl); - return(-1); - } + // According to DDI0419C, Table C1-7 firstly force halt + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + STLINK_REG_DHCSR_C_HALT); + // and only then disable interrupts + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + STLINK_REG_DHCSR_C_HALT | + STLINK_REG_DHCSR_C_MASKINTS); + + // disable DMA + set_dma_state(sl, fl, 0); + + // wait for ongoing op to finish + wait_flash_busy(sl); + // Clear errors + clear_flash_error(sl); + + if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || + (sl->flash_type == STLINK_FLASH_TYPE_F7) || + (sl->flash_type == STLINK_FLASH_TYPE_L4)) { + ILOG("Starting Flash write for F2/F4/F7/L4\n"); + + // Flash loader initialisation + if (stlink_flash_loader_init(sl, fl) == -1) { + ELOG("stlink_flash_loader_init() == -1\n"); + return (-1); + } + + unlock_flash_if(sl); // first unlock the cr + + int voltage; + if (sl->version.stlink_v == 1) { + WLOG("STLINK V1 cannot read voltage, use default voltage 3.2V\n"); + voltage = 3200; + } else { + voltage = stlink_target_voltage(sl); + } - lock_flash(sl); + if (voltage == -1) { + ELOG("Failed to read Target voltage\n"); + return (-1); + } - if (sl->verbose >= 1) { - // show progress; writing procedure is slow and previous errors are misleading - fprintf(stdout, "\r%3u/%3u pages written", ++write_block_count, - (unsigned int)((len + sl->flash_pgsz - 1) / sl->flash_pgsz)); - fflush(stdout); - } - } - if (sl->verbose >= 1) { - fprintf(stdout, "\n"); - } - } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { - for (off = 0; off < len;) { - // Program STM32H7x with 64-byte Flash words - size_t chunk = (len - off > 64) ? 64 : len - off; - memcpy(sl->q_buf, base + off, chunk); - stlink_write_mem32(sl, addr + (uint32_t)off, 64); - wait_flash_busy(sl); - - off += chunk; - - if (sl->verbose >= 1) { - // show progress - fprintf(stdout, "\r%u/%u bytes written", (unsigned int)off, (unsigned int)len); - fflush(stdout); - } - } - if (sl->verbose >= 1) { - fprintf(stdout, "\n"); - } + if (sl->flash_type == STLINK_FLASH_TYPE_L4) { + // L4 does not have a byte-write mode + if (voltage < 1710) { + ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage); + return (-1); + } + } else { + if (voltage > 2700) { + ILOG("enabling 32-bit flash writes\n"); + write_flash_cr_psiz(sl, 2, BANK_1); + } else { + ILOG("Target voltage (%d mV) too low for 32-bit flash, " + "using 8-bit flash writes\n", + voltage); + write_flash_cr_psiz(sl, 0, BANK_1); + } + } + + // set programming mode + set_flash_cr_pg(sl, BANK_1); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + ILOG("Starting Flash write for WB/G0/G4\n"); + + unlock_flash_if(sl); // unlock flash if necessary + set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + ILOG("Starting Flash write for L0\n"); + + uint32_t val; + uint32_t flash_regs_base; + if (sl->chip_id == STLINK_CHIPID_STM32_L0 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || + sl->chip_id == STLINK_CHIPID_STM32_L011) { + flash_regs_base = STM32L0_FLASH_REGS_ADDR; } else { - return(-1); + flash_regs_base = STM32L_FLASH_REGS_ADDR; } - return check_flash_error(sl); -} + // disable pecr protection + stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, + FLASH_L0_PEKEY1); + stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, + FLASH_L0_PEKEY2); -int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { - uint32_t dhcsr; - - if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || - (sl->flash_type == STLINK_FLASH_TYPE_F7) || - (sl->flash_type == STLINK_FLASH_TYPE_L4) || - (sl->flash_type == STLINK_FLASH_TYPE_WB) || - (sl->flash_type == STLINK_FLASH_TYPE_G0) || - (sl->flash_type == STLINK_FLASH_TYPE_G4) || - (sl->flash_type == STLINK_FLASH_TYPE_H7)) { - - clear_flash_cr_pg(sl, BANK_1); - if (sl->flash_type == STLINK_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { - clear_flash_cr_pg(sl, BANK_2); - } - lock_flash(sl); - } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - uint32_t val; - uint32_t flash_regs_base; - if (sl->chip_id == STLINK_CHIPID_STM32_L0 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || - sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || - sl->chip_id == STLINK_CHIPID_STM32_L011) { - flash_regs_base = STM32L0_FLASH_REGS_ADDR; - } else { - flash_regs_base = STM32L_FLASH_REGS_ADDR; - } - // reset lock bits - stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); - val |= (1 << 0) | (1 << 1) | (1 << 2); - stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + // check pecr.pelock is cleared + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + if (val & (1 << 0)) { + ELOG("pecr.pelock not clear\n"); + return (-1); + } + + // unlock program memory + stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, + FLASH_L0_PRGKEY1); + stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, + FLASH_L0_PRGKEY2); + + // check pecr.prglock is cleared + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + if (val & (1 << 1)) { + ELOG("pecr.prglock not clear\n"); + return (-1); + } + } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { + ILOG("Starting Flash write for VL/F0/F3/F1_XL\n"); + + // flash loader initialisation + if (stlink_flash_loader_init(sl, fl) == -1) { + ELOG("stlink_flash_loader_init() == -1\n"); + return (-1); + } + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + ILOG("Starting Flash write for H7\n"); + + unlock_flash_if(sl); // unlock the cr + set_flash_cr_pg(sl, BANK_1); // set programming mode + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + set_flash_cr_pg(sl, BANK_2); + } + if (sl->chip_id != STLINK_CHIPID_STM32_H7AX) { + // set parallelism + write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1); + if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2); + } + } + } else { + ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id); + return (-1); + } + + return (0); +} + +int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, + stm32_addr_t addr, uint8_t *base, uint32_t len) { + size_t off; + if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || + (sl->flash_type == STLINK_FLASH_TYPE_F7) || + (sl->flash_type == STLINK_FLASH_TYPE_L4)) { + size_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000; + for (off = 0; off < len;) { + size_t size = len - off > buf_size ? buf_size : len - off; + if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off, + size) == -1) { + ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", + (unsigned)(addr + off)); + check_flash_error(sl); + return (-1); + } + + off += size; + } + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { + DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz)); + for (off = 0; off < len; off += sizeof(uint32_t)) { + uint32_t data; + + if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { + fprintf(stdout, "\r%3u/%3u pages written", + (unsigned int)(off / sl->flash_pgsz), + (unsigned int)(len / sl->flash_pgsz)); + fflush(stdout); + } + + write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); + stlink_write_debug32(sl, addr + (uint32_t)off, data); + wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear } + fprintf(stdout, "\n"); - // enable interrupt - if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) { - stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | - STLINK_REG_DHCSR_C_DEBUGEN | - (dhcsr&(~STLINK_REG_DHCSR_C_MASKINTS))); + // flash writes happen as 2 words at a time + if ((off / sizeof(uint32_t)) % 2 != 0) { + stlink_write_debug32(sl, addr + (uint32_t)off, + 0); // write a single word of zeros + wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear + } + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + uint32_t val; + uint32_t flash_regs_base; + uint32_t pagesize; + + if (sl->chip_id == STLINK_CHIPID_STM32_L0 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || + sl->chip_id == STLINK_CHIPID_STM32_L011) { + flash_regs_base = STM32L0_FLASH_REGS_ADDR; + pagesize = L0_WRITE_BLOCK_SIZE; + } else { + flash_regs_base = STM32L_FLASH_REGS_ADDR; + pagesize = L1_WRITE_BLOCK_SIZE; } - // restore DMA state - set_dma_state(sl, fl, 1); - - return(0); -} - -int stlink_write_flash( - stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint8_t eraseonly) { - size_t off; - int ret; - flash_loader_t fl; - ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); - // check addr range is inside the flash - stlink_calculate_pagesize(sl, addr); - - if (addr < sl->flash_base) { - ELOG("addr too low %#x < %#x\n", addr, sl->flash_base); - return(-1); - } else if ((addr + len) < addr) { - ELOG("addr overruns\n"); - return(-1); - } else if ((addr + len) > (sl->flash_base + sl->flash_size)) { - ELOG("addr too high\n"); - return(-1); - } else if (addr & 1) { - ELOG("unaligned addr 0x%x\n", addr); - return(-1); - } else if (len & 1) { - WLOG("unaligned len 0x%x -- padding with zero\n", len); - len += 1; - } else if (addr & (sl->flash_pgsz - 1)) { - ELOG("addr not a multiple of current pagesize (%u bytes), not supported, " - "check page start address and compare with flash module organisation " - "in related ST reference manual of your device.\n", (unsigned)(sl->flash_pgsz)); - return(-1); + off = 0; + + if (len > pagesize) { + if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) { + // this may happen on a blank device! + WLOG("\nwrite_half_pages failed == -1\n"); + } else { + off = (size_t)(len / pagesize) * pagesize; + } } - // make sure we've loaded the context with the chip details - stlink_core_id(sl); + // write remaining word in program memory + for (; off < len; off += sizeof(uint32_t)) { + uint32_t data; - // Erase each page - int page_count = 0; + if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { + fprintf(stdout, "\r%3u/%3u pages written", + (unsigned int)(off / sl->flash_pgsz), + (unsigned int)(len / sl->flash_pgsz)); + fflush(stdout); + } - for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + (uint32_t)off)) { - // addr must be an addr inside the page - if (stlink_erase_flash_page(sl, addr + (uint32_t)off) == -1) { - ELOG("Failed to erase_flash_page(%#x) == -1\n", (unsigned)(addr + off)); - return(-1); - } + write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); + stlink_write_debug32(sl, addr + (uint32_t)off, data); - ILOG("Flash page at addr: 0x%08lx erased\n", (unsigned long)(addr + off)); - page_count++; + // wait for sr.busy to be cleared + do { + stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val); + } while ((val & (1 << 0)) != 0); + + // TODO: check redo write operation } + fprintf(stdout, "\n"); + } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) { + int write_block_count = 0; + for (off = 0; off < len; off += sl->flash_pgsz) { + // adjust last write size + size_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off; + + // unlock and set programming mode + unlock_flash_if(sl); + + DLOG("Finished unlocking flash, running loader!\n"); + + if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off, + size) == -1) { + ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", + (unsigned)(addr + off)); + check_flash_error(sl); + return (-1); + } + + lock_flash(sl); + + if (sl->verbose >= 1) { + // show progress; writing procedure is slow and previous errors are + // misleading + fprintf(stdout, "\r%3u/%3u pages written", ++write_block_count, + (unsigned int)((len + sl->flash_pgsz - 1) / sl->flash_pgsz)); + fflush(stdout); + } + } + if (sl->verbose >= 1) { + fprintf(stdout, "\n"); + } + } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { + for (off = 0; off < len;) { + // Program STM32H7x with 64-byte Flash words + size_t chunk = (len - off > 64) ? 64 : len - off; + memcpy(sl->q_buf, base + off, chunk); + stlink_write_mem32(sl, addr + (uint32_t)off, 64); + wait_flash_busy(sl); + + off += chunk; + + if (sl->verbose >= 1) { + // show progress + fprintf(stdout, "\r%u/%u bytes written", (unsigned int)off, + (unsigned int)len); + fflush(stdout); + } + } + if (sl->verbose >= 1) { + fprintf(stdout, "\n"); + } + } else { + return (-1); + } + + return check_flash_error(sl); +} - ILOG("Finished erasing %d pages of %u (%#x) bytes\n", - page_count, (unsigned)(sl->flash_pgsz), (unsigned)(sl->flash_pgsz)); +int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { + uint32_t dhcsr; - if (eraseonly) { return(0); } + if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || + (sl->flash_type == STLINK_FLASH_TYPE_F7) || + (sl->flash_type == STLINK_FLASH_TYPE_L4) || + (sl->flash_type == STLINK_FLASH_TYPE_WB) || + (sl->flash_type == STLINK_FLASH_TYPE_G0) || + (sl->flash_type == STLINK_FLASH_TYPE_G4) || + (sl->flash_type == STLINK_FLASH_TYPE_H7)) { - ret = stlink_flashloader_start(sl, &fl); - if (ret) - return ret; - ret = stlink_flashloader_write(sl, &fl, addr, base, len); - if (ret) - return ret; - ret = stlink_flashloader_stop(sl, &fl); - if (ret) - return ret; + clear_flash_cr_pg(sl, BANK_1); + if (sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + clear_flash_cr_pg(sl, BANK_2); + } + lock_flash(sl); + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + uint32_t val; + uint32_t flash_regs_base; + if (sl->chip_id == STLINK_CHIPID_STM32_L0 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || + sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 || + sl->chip_id == STLINK_CHIPID_STM32_L011) { + flash_regs_base = STM32L0_FLASH_REGS_ADDR; + } else { + flash_regs_base = STM32L_FLASH_REGS_ADDR; + } + // reset lock bits + stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); + val |= (1 << 0) | (1 << 1) | (1 << 2); + stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); + } + + // enable interrupt + if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) { + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + (dhcsr & (~STLINK_REG_DHCSR_C_MASKINTS))); + } + + // restore DMA state + set_dma_state(sl, fl, 1); + + return (0); +} + +int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, + uint32_t len, uint8_t eraseonly) { + size_t off; + int ret; + flash_loader_t fl; + ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, + len, addr, addr); + // check addr range is inside the flash + stlink_calculate_pagesize(sl, addr); + + if (addr < sl->flash_base) { + ELOG("addr too low %#x < %#x\n", addr, sl->flash_base); + return (-1); + } else if ((addr + len) < addr) { + ELOG("addr overruns\n"); + return (-1); + } else if ((addr + len) > (sl->flash_base + sl->flash_size)) { + ELOG("addr too high\n"); + return (-1); + } else if (addr & 1) { + ELOG("unaligned addr 0x%x\n", addr); + return (-1); + } else if (len & 1) { + WLOG("unaligned len 0x%x -- padding with zero\n", len); + len += 1; + } else if (addr & (sl->flash_pgsz - 1)) { + ELOG("addr not a multiple of current pagesize (%u bytes), not supported, " + "check page start address and compare with flash module organisation " + "in related ST reference manual of your device.\n", + (unsigned)(sl->flash_pgsz)); + return (-1); + } + + // make sure we've loaded the context with the chip details + stlink_core_id(sl); + + // Erase each page + int page_count = 0; + + for (off = 0; off < len; + off += stlink_calculate_pagesize(sl, addr + (uint32_t)off)) { + // addr must be an addr inside the page + if (stlink_erase_flash_page(sl, addr + (uint32_t)off) == -1) { + ELOG("Failed to erase_flash_page(%#x) == -1\n", (unsigned)(addr + off)); + return (-1); + } + + ILOG("Flash page at addr: 0x%08lx erased\n", (unsigned long)(addr + off)); + page_count++; + } + + ILOG("Finished erasing %d pages of %u (%#x) bytes\n", page_count, + (unsigned)(sl->flash_pgsz), (unsigned)(sl->flash_pgsz)); + + if (eraseonly) { + return (0); + } + + ret = stlink_flashloader_start(sl, &fl); + if (ret) + return ret; + ret = stlink_flashloader_write(sl, &fl, addr, base, len); + if (ret) + return ret; + ret = stlink_flashloader_stop(sl, &fl); + if (ret) + return ret; - return(stlink_verify_write_flash(sl, addr, base, len)); + return (stlink_verify_write_flash(sl, addr, base, len)); } // TODO: length not checked -static uint8_t stlink_parse_hex(const char* hex) { - uint8_t d[2]; - - for (int i = 0; i < 2; ++i) { - char c = *(hex + i); - - if (c >= '0' && c <= '9') { - d[i] = c - '0'; - } else if (c >= 'A' && c <= 'F') { - d[i] = c - 'A' + 10; - } else if (c >= 'a' && c <= 'f') { - d[i] = c - 'a' + 10; - } else { - return(0); // error - } +static uint8_t stlink_parse_hex(const char *hex) { + uint8_t d[2]; + + for (int i = 0; i < 2; ++i) { + char c = *(hex + i); + + if (c >= '0' && c <= '9') { + d[i] = c - '0'; + } else if (c >= 'A' && c <= 'F') { + d[i] = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + d[i] = c - 'a' + 10; + } else { + return (0); // error } + } - return((d[0] << 4) | (d[1])); + return ((d[0] << 4) | (d[1])); } -int stlink_parse_ihex(const char* path, uint8_t erased_pattern, uint8_t * * mem, size_t * size, - uint32_t * begin) { - int res = 0; - *begin = UINT32_MAX; - uint8_t* data = NULL; - uint32_t end = 0; - bool eof_found = false; +int stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem, + size_t *size, uint32_t *begin) { + int res = 0; + *begin = UINT32_MAX; + uint8_t *data = NULL; + uint32_t end = 0; + bool eof_found = false; - for (int scan = 0; (res == 0) && (scan < 2); ++scan) { - // parse file two times - first to find memory range, second - to fill it - if (scan == 1) { - if (!eof_found) { - ELOG("No EoF recond\n"); - res = -1; - break; - } + for (int scan = 0; (res == 0) && (scan < 2); ++scan) { + // parse file two times - first to find memory range, second - to fill it + if (scan == 1) { + if (!eof_found) { + ELOG("No EoF recond\n"); + res = -1; + break; + } - if (*begin >= end) { - ELOG("No data found in file\n"); - res = -1; - break; - } + if (*begin >= end) { + ELOG("No data found in file\n"); + res = -1; + break; + } - *size = (end - *begin) + 1; - data = calloc(*size, 1); // use calloc to get NULL if out of memory + *size = (end - *begin) + 1; + data = calloc(*size, 1); // use calloc to get NULL if out of memory - if (!data) { - ELOG("Cannot allocate %u bytes\n", (unsigned)(*size)); - res = -1; - break; - } + if (!data) { + ELOG("Cannot allocate %u bytes\n", (unsigned)(*size)); + res = -1; + break; + } - memset(data, erased_pattern, *size); - } + memset(data, erased_pattern, *size); + } - FILE* file = fopen(path, "r"); + FILE *file = fopen(path, "r"); - if (!file) { - ELOG("Cannot open file\n"); - res = -1; - break; - } + if (!file) { + ELOG("Cannot open file\n"); + res = -1; + break; + } - uint32_t lba = 0; - char line[1 + 5 * 2 + 255 * 2 + 2]; + uint32_t lba = 0; + char line[1 + 5 * 2 + 255 * 2 + 2]; - while (fgets(line, sizeof(line), file)) { - if (line[0] == '\n' || line[0] == '\r') { continue; } // skip empty lines + while (fgets(line, sizeof(line), file)) { + if (line[0] == '\n' || line[0] == '\r') { + continue; + } // skip empty lines - if (line[0] != ':') { // no marker - wrong file format - ELOG("Wrong file format - no marker\n"); - res = -1; - break; - } + if (line[0] != ':') { // no marker - wrong file format + ELOG("Wrong file format - no marker\n"); + res = -1; + break; + } - size_t l = strlen(line); + size_t l = strlen(line); - while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) { --l; } // trim EoL + while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) { + --l; + } // trim EoL - if ((l < 11) || (l == (sizeof(line) - 1))) { // line too short or long - wrong file format - ELOG("Wrong file format - wrong line length\n"); - res = -1; - break; - } + if ((l < 11) || + (l == + (sizeof(line) - 1))) { // line too short or long - wrong file format + ELOG("Wrong file format - wrong line length\n"); + res = -1; + break; + } - uint8_t chksum = 0; // check sum + uint8_t chksum = 0; // check sum - for (size_t i = 1; i < l; i += 2) { chksum += stlink_parse_hex(line + i); } + for (size_t i = 1; i < l; i += 2) { + chksum += stlink_parse_hex(line + i); + } - if (chksum != 0) { - ELOG("Wrong file format - checksum mismatch\n"); - res = -1; - break; - } + if (chksum != 0) { + ELOG("Wrong file format - checksum mismatch\n"); + res = -1; + break; + } - uint8_t reclen = stlink_parse_hex(line + 1); + uint8_t reclen = stlink_parse_hex(line + 1); - if (((uint32_t)reclen + 5) * 2 + 1 != l) { - ELOG("Wrong file format - record length mismatch\n"); - res = -1; - break; - } + if (((uint32_t)reclen + 5) * 2 + 1 != l) { + ELOG("Wrong file format - record length mismatch\n"); + res = -1; + break; + } - uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) | - ((uint16_t)stlink_parse_hex(line + 5)); - uint8_t rectype = stlink_parse_hex(line + 7); - - switch (rectype) { - case 0: /* Data */ - if (scan == 0) { - uint32_t b = lba + offset; - uint32_t e = b + reclen - 1; - - if (b < *begin) { *begin = b; } - - if (e > end) { end = e; } - } else { - for (uint8_t i = 0; i < reclen; ++i) { - uint8_t b = stlink_parse_hex(line + 9 + i * 2); - uint32_t addr = lba + offset + i; - - if (addr >= *begin && addr <= end) { data[addr - *begin] = b; } - } - } - break; - case 1: /* EoF */ - eof_found = true; - break; - case 2: /* Extended Segment Address, unexpected */ - res = -1; - break; - case 3: /* Start Segment Address, unexpected */ - res = -1; - break; - case 4: /* Extended Linear Address */ - if (reclen == 2) { - lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) | - ((uint32_t)stlink_parse_hex(line + 11) << 16); - } else { - ELOG("Wrong file format - wrong LBA length\n"); - res = -1; - } - break; - case 5: /* Start Linear Address - expected, but ignore */ - break; - default: - ELOG("Wrong file format - unexpected record type %d\n", rectype); - res = -1; - } + uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) | + ((uint16_t)stlink_parse_hex(line + 5)); + uint8_t rectype = stlink_parse_hex(line + 7); - if (res != 0) { break; } - } + switch (rectype) { + case 0: /* Data */ + if (scan == 0) { + uint32_t b = lba + offset; + uint32_t e = b + reclen - 1; - fclose(file); - } + if (b < *begin) { + *begin = b; + } - if (res == 0) { - *mem = data; - } else { - free(data); - } + if (e > end) { + end = e; + } + } else { + for (uint8_t i = 0; i < reclen; ++i) { + uint8_t b = stlink_parse_hex(line + 9 + i * 2); + uint32_t addr = lba + offset + i; - return(res); -} + if (addr >= *begin && addr <= end) { + data[addr - *begin] = b; + } + } + } + break; + case 1: /* EoF */ + eof_found = true; + break; + case 2: /* Extended Segment Address, unexpected */ + res = -1; + break; + case 3: /* Start Segment Address, unexpected */ + res = -1; + break; + case 4: /* Extended Linear Address */ + if (reclen == 2) { + lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) | + ((uint32_t)stlink_parse_hex(line + 11) << 16); + } else { + ELOG("Wrong file format - wrong LBA length\n"); + res = -1; + } + break; + case 5: /* Start Linear Address - expected, but ignore */ + break; + default: + ELOG("Wrong file format - unexpected record type %d\n", rectype); + res = -1; + } -uint8_t stlink_get_erased_pattern(stlink_t *sl) { - if (sl->flash_type == STLINK_FLASH_TYPE_L0) { - return(0x00); - } else { - return(0xff); + if (res != 0) { + break; + } } -} -int stlink_mwrite_flash(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_t addr) { - /* Write the block in flash at addr */ - int err; - unsigned int num_empty, idx; - uint8_t erased_pattern = stlink_get_erased_pattern(sl); + fclose(file); + } - /* - * This optimisation may cause unexpected garbage data remaining. - * Therfore it is turned off by default. - */ - if (sl->opt) { - idx = (unsigned int)length; + if (res == 0) { + *mem = data; + } else { + free(data); + } + + return (res); +} - for (num_empty = 0; num_empty != length; ++num_empty) - if (data[--idx] != erased_pattern) { break; } +uint8_t stlink_get_erased_pattern(stlink_t *sl) { + if (sl->flash_type == STLINK_FLASH_TYPE_L0) { + return (0x00); + } else { + return (0xff); + } +} + +int stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, + stm32_addr_t addr) { + /* Write the block in flash at addr */ + int err; + unsigned int num_empty, idx; + uint8_t erased_pattern = stlink_get_erased_pattern(sl); + + /* + * This optimisation may cause unexpected garbage data remaining. + * Therfore it is turned off by default. + */ + if (sl->opt) { + idx = (unsigned int)length; + + for (num_empty = 0; num_empty != length; ++num_empty) + if (data[--idx] != erased_pattern) { + break; + } - num_empty -= (num_empty & 3); // Round down to words + num_empty -= (num_empty & 3); // Round down to words - if (num_empty != 0) { - ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); - } - } else { - num_empty = 0; + if (num_empty != 0) { + ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, + erased_pattern); } + } else { + num_empty = 0; + } - /* - * TODO: investigate a kind of weird behaviour here: - * If the file is identified to be all-empty and four-bytes aligned, - * still flash the whole file even if ignoring message is printed. - */ - err = stlink_write_flash(sl, addr, data, - (num_empty == length) ? (uint32_t)length : (uint32_t)length - num_empty, - num_empty == length); - stlink_fwrite_finalize(sl, addr); - return(err); + /* + * TODO: investigate a kind of weird behaviour here: + * If the file is identified to be all-empty and four-bytes aligned, + * still flash the whole file even if ignoring message is printed. + */ + err = stlink_write_flash(sl, addr, data, + (num_empty == length) ? (uint32_t)length + : (uint32_t)length - num_empty, + num_empty == length); + stlink_fwrite_finalize(sl, addr); + return (err); } /** @@ -3645,49 +3791,53 @@ int stlink_mwrite_flash(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr * @param addr where to start writing * @return 0 on success, -ve on failure. */ -int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) { - /* Write the file in flash at addr */ - int err; - unsigned int num_empty, idx; - uint8_t erased_pattern = stlink_get_erased_pattern(sl); - mapped_file_t mf = MAPPED_FILE_INITIALIZER; - - if (map_file(&mf, path) == -1) { - ELOG("map_file() == -1\n"); - return(-1); +int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { + /* Write the file in flash at addr */ + int err; + unsigned int num_empty, idx; + uint8_t erased_pattern = stlink_get_erased_pattern(sl); + mapped_file_t mf = MAPPED_FILE_INITIALIZER; + + if (map_file(&mf, path) == -1) { + ELOG("map_file() == -1\n"); + return (-1); + } + + printf("file %s ", path); + md5_calculate(&mf); + stlink_checksum(&mf); + + if (sl->opt) { + idx = (unsigned int)mf.len; + + for (num_empty = 0; num_empty != mf.len; ++num_empty) { + if (mf.base[--idx] != erased_pattern) { + break; + } } - printf("file %s ", path); - md5_calculate(&mf); - stlink_checksum(&mf); - - if (sl->opt) { - idx = (unsigned int)mf.len; + num_empty -= (num_empty & 3); // round down to words - for (num_empty = 0; num_empty != mf.len; ++num_empty) { - if (mf.base[--idx] != erased_pattern) { break; } - } - - num_empty -= (num_empty & 3); // round down to words - - if (num_empty != 0) { - ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); - } - } else { - num_empty = 0; + if (num_empty != 0) { + ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, + erased_pattern); } + } else { + num_empty = 0; + } - /* - * TODO: investigate a kind of weird behaviour here: - * If the file is identified to be all-empty and four-bytes aligned, - * still flash the whole file even if ignoring message is printed. - */ - err = stlink_write_flash(sl, addr, mf.base, - (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty, - num_empty == mf.len); - stlink_fwrite_finalize(sl, addr); - unmap_file(&mf); - return(err); + /* + * TODO: investigate a kind of weird behaviour here: + * If the file is identified to be all-empty and four-bytes aligned, + * still flash the whole file even if ignoring message is printed. + */ + err = stlink_write_flash(sl, addr, mf.base, + (num_empty == mf.len) ? (uint32_t)mf.len + : (uint32_t)mf.len - num_empty, + num_empty == mf.len); + stlink_fwrite_finalize(sl, addr); + unmap_file(&mf); + return (err); } /** @@ -3697,35 +3847,35 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) { * @param base option bytes to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_gx( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - /* Write options bytes */ - uint32_t val; - int ret = 0; - (void)len; - uint32_t data; +static int stlink_write_option_bytes_gx(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { + /* Write options bytes */ + uint32_t val; + int ret = 0; + (void)len; + uint32_t data; - clear_flash_error(sl); + clear_flash_error(sl); - write_uint32((unsigned char*)&data, *(uint32_t*)(base)); - WLOG("Writing option bytes %#10x to %#10x\n", data, addr); - stlink_write_debug32(sl, STM32Gx_FLASH_OPTR, data); + write_uint32((unsigned char *)&data, *(uint32_t *)(base)); + WLOG("Writing option bytes %#10x to %#10x\n", data, addr); + stlink_write_debug32(sl, STM32Gx_FLASH_OPTR, data); - // Set Options Start bit - stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); - val |= (1 << STM32Gx_FLASH_CR_OPTSTRT); - stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); + // Set Options Start bit + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1 << STM32Gx_FLASH_CR_OPTSTRT); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); - wait_flash_busy(sl); + wait_flash_busy(sl); - ret = check_flash_error(sl); + ret = check_flash_error(sl); - // Reload options - stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); - val |= (1 << STM32Gx_FLASH_CR_OBL_LAUNCH); - stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); + // Reload options + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1 << STM32Gx_FLASH_CR_OBL_LAUNCH); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); - return(ret); + return (ret); } /** @@ -3735,36 +3885,39 @@ static int stlink_write_option_bytes_gx( * @param base option bytes to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_l0( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - uint32_t flash_base = get_stm32l0_flash_base(sl); - uint32_t val; - uint32_t data; - int ret = 0; - - // Clear errors - clear_flash_error(sl); +static int stlink_write_option_bytes_l0(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { + uint32_t flash_base = get_stm32l0_flash_base(sl); + uint32_t val; + uint32_t data; + int ret = 0; - while (len != 0) { - write_uint32((unsigned char*)&data, *(uint32_t*)(base)); // write options bytes + // Clear errors + clear_flash_error(sl); - WLOG("Writing option bytes %#10x to %#10x\n", data, addr); - stlink_write_debug32(sl, addr, data); - wait_flash_busy(sl); + while (len != 0) { + write_uint32((unsigned char *)&data, + *(uint32_t *)(base)); // write options bytes - if ((ret = check_flash_error(sl))) { break; } + WLOG("Writing option bytes %#10x to %#10x\n", data, addr); + stlink_write_debug32(sl, addr, data); + wait_flash_busy(sl); - len -= 4; - addr += 4; - base += 4; + if ((ret = check_flash_error(sl))) { + break; } - // Reload options - stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val); - val |= (1 << STM32L0_FLASH_OBL_LAUNCH); - stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val); + len -= 4; + addr += 4; + base += 4; + } + + // Reload options + stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val); + val |= (1 << STM32L0_FLASH_OBL_LAUNCH); + stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val); - return(ret); + return (ret); } /** @@ -3774,67 +3927,67 @@ static int stlink_write_option_bytes_l0( * @param base option bytes to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_l4( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { +static int stlink_write_option_bytes_l4(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { - uint32_t val; - int ret = 0; - (void)addr; - (void)len; + uint32_t val; + int ret = 0; + (void)addr; + (void)len; - // Clear errors - clear_flash_error(sl); + // Clear errors + clear_flash_error(sl); - // write options bytes - uint32_t data; - write_uint32((unsigned char*)&data, *(uint32_t*)(base)); - WLOG("Writing option bytes 0x%04x\n", data); - stlink_write_debug32(sl, STM32L4_FLASH_OPTR, data); + // write options bytes + uint32_t data; + write_uint32((unsigned char *)&data, *(uint32_t *)(base)); + WLOG("Writing option bytes 0x%04x\n", data); + stlink_write_debug32(sl, STM32L4_FLASH_OPTR, data); - // set options start bit - stlink_read_debug32(sl, STM32L4_FLASH_CR, &val); - val |= (1 << STM32L4_FLASH_CR_OPTSTRT); - stlink_write_debug32(sl, STM32L4_FLASH_CR, val); + // set options start bit + stlink_read_debug32(sl, STM32L4_FLASH_CR, &val); + val |= (1 << STM32L4_FLASH_CR_OPTSTRT); + stlink_write_debug32(sl, STM32L4_FLASH_CR, val); - wait_flash_busy(sl); - ret = check_flash_error(sl); + wait_flash_busy(sl); + ret = check_flash_error(sl); - // apply options bytes immediate - stlink_read_debug32(sl, STM32L4_FLASH_CR, &val); - val |= (1 << STM32L4_FLASH_CR_OBL_LAUNCH); - stlink_write_debug32(sl, STM32L4_FLASH_CR, val); + // apply options bytes immediate + stlink_read_debug32(sl, STM32L4_FLASH_CR, &val); + val |= (1 << STM32L4_FLASH_CR_OBL_LAUNCH); + stlink_write_debug32(sl, STM32L4_FLASH_CR, val); - return(ret); + return (ret); } - /** * Write option bytes * @param sl * @param option_byte value to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_f4( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - uint32_t option_byte; - int ret = 0; - (void)addr; - (void)len; - - // Clear errors - clear_flash_error(sl); +static int stlink_write_option_bytes_f4(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { + uint32_t option_byte; + int ret = 0; + (void)addr; + (void)len; - write_uint32((unsigned char*)&option_byte, *(uint32_t*)(base)); + // Clear errors + clear_flash_error(sl); - // write option byte, ensuring we dont lock opt, and set strt bit - stlink_write_debug32(sl, FLASH_F4_OPTCR, - (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) | (1 << FLASH_F4_OPTCR_START)); + write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); - wait_flash_busy(sl); - ret = check_flash_error(sl); + // write option byte, ensuring we dont lock opt, and set strt bit + stlink_write_debug32(sl, FLASH_F4_OPTCR, + (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) | + (1 << FLASH_F4_OPTCR_START)); - // option bytes are reloaded at reset only, no obl. */ - return(ret); + wait_flash_busy(sl); + ret = check_flash_error(sl); + + // option bytes are reloaded at reset only, no obl. */ + return (ret); } /** @@ -3843,47 +3996,54 @@ static int stlink_write_option_bytes_f4( * @param option_byte value to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_f7(stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - uint32_t option_byte; - int ret = 0; +static int stlink_write_option_bytes_f7(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { + uint32_t option_byte; + int ret = 0; - // Clear errors - clear_flash_error(sl); + // Clear errors + clear_flash_error(sl); - ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t*) (base), addr); - write_uint32((unsigned char*) &option_byte, *(uint32_t*) (base)); - ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr); + ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), + addr); + write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); + ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr); - if ( addr == 0 ) { - addr = FLASH_F7_OPTCR; - ILOG("No address provided, using %#10x\n", addr); - } + if (addr == 0) { + addr = FLASH_F7_OPTCR; + ILOG("No address provided, using %#10x\n", addr); + } - if ( addr == FLASH_F7_OPTCR ) { - /* write option byte, ensuring we dont lock opt, and set strt bit */ - stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); - } else if ( addr == FLASH_F7_OPTCR1 ) { - // Read FLASH_F7_OPTCR - uint32_t oldvalue; - stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue); - /* write option byte */ - stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte); - // Write FLASH_F7_OPTCR lock and start address - stlink_write_debug32(sl, FLASH_F7_OPTCR, (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); - } else { - WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr); - stlink_write_debug32(sl, addr, option_byte); - } + if (addr == FLASH_F7_OPTCR) { + /* write option byte, ensuring we dont lock opt, and set strt bit */ + stlink_write_debug32(sl, FLASH_F7_OPTCR, + (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) | + (1 << FLASH_F7_OPTCR_START)); + } else if (addr == FLASH_F7_OPTCR1) { + // Read FLASH_F7_OPTCR + uint32_t oldvalue; + stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue); + /* write option byte */ + stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte); + // Write FLASH_F7_OPTCR lock and start address + stlink_write_debug32(sl, FLASH_F7_OPTCR, + (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) | + (1 << FLASH_F7_OPTCR_START)); + } else { + WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr); + stlink_write_debug32(sl, addr, option_byte); + } - wait_flash_busy(sl); + wait_flash_busy(sl); - ret = check_flash_error(sl); - if (!ret) - ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t*) base, addr); + ret = check_flash_error(sl); + if (!ret) + ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, + addr); - /* option bytes are reloaded at reset only, no obl. */ + /* option bytes are reloaded at reset only, no obl. */ - return ret; + return ret; } /** @@ -3894,64 +4054,67 @@ static int stlink_write_option_bytes_f7(stlink_t *sl, uint8_t* base, stm32_addr_ * @param len number of bytes to write (must be multiple of 4) * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_h7( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - uint32_t val; - uint32_t data; - - // Wait until previous flash option has completed - wait_flash_busy(sl); - - // Clear previous error - stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); - - while (len != 0) { - switch (addr) { - case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG - case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1 - case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1 - case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1 - case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG - /* Write to FLASH_xxx_PRG registers */ - write_uint32((unsigned char*)&data, *(uint32_t*)(base)); // write options bytes - - WLOG("Writing option bytes %#10x to %#10x\n", data, addr); - - /* Skip if the value in the CUR register is identical */ - stlink_read_debug32(sl, addr - 4, &val); - if (val == data) { - break; - } - - /* Write new option byte values and start modification */ - stlink_write_debug32(sl, addr, data); - stlink_read_debug32(sl, FLASH_H7_OPTCR, &val); - val |= (1 << FLASH_H7_OPTCR_OPTSTART); - stlink_write_debug32(sl, FLASH_H7_OPTCR, val); - - /* Wait for the option bytes modification to complete */ - do { - stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val); - } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0); - - /* Check for errors */ - if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) { - stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); - return -1; - } - break; - - default: - /* Skip non-programmable registers */ - break; - } +static int stlink_write_option_bytes_h7(stlink_t *sl, uint8_t *base, + stm32_addr_t addr, uint32_t len) { + uint32_t val; + uint32_t data; + + // Wait until previous flash option has completed + wait_flash_busy(sl); + + // Clear previous error + stlink_write_debug32(sl, FLASH_H7_OPTCCR, + 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); + + while (len != 0) { + switch (addr) { + case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG + case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1 + case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1 + case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1 + case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG + /* Write to FLASH_xxx_PRG registers */ + write_uint32((unsigned char *)&data, + *(uint32_t *)(base)); // write options bytes + + WLOG("Writing option bytes %#10x to %#10x\n", data, addr); + + /* Skip if the value in the CUR register is identical */ + stlink_read_debug32(sl, addr - 4, &val); + if (val == data) { + break; + } + + /* Write new option byte values and start modification */ + stlink_write_debug32(sl, addr, data); + stlink_read_debug32(sl, FLASH_H7_OPTCR, &val); + val |= (1 << FLASH_H7_OPTCR_OPTSTART); + stlink_write_debug32(sl, FLASH_H7_OPTCR, val); + + /* Wait for the option bytes modification to complete */ + do { + stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val); + } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0); + + /* Check for errors */ + if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) { + stlink_write_debug32(sl, FLASH_H7_OPTCCR, + 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); + return -1; + } + break; - len -= 4; - addr += 4; - base += 4; + default: + /* Skip non-programmable registers */ + break; } - return 0; + len -= 4; + addr += 4; + base += 4; + } + + return 0; } /** @@ -3960,8 +4123,9 @@ static int stlink_write_option_bytes_h7( * @param option_byte value to write * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register_Gx(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, option_byte); +int stlink_read_option_control_register_Gx(stlink_t *sl, + uint32_t *option_byte) { + return stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, option_byte); } /** @@ -3970,8 +4134,8 @@ int stlink_read_option_control_register_Gx(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to write * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_Gx(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_option_control_register_Gx(sl, option_byte); +int stlink_read_option_bytes_Gx(stlink_t *sl, uint32_t *option_byte) { + return stlink_read_option_control_register_Gx(sl, option_byte); } /** @@ -3980,8 +4144,9 @@ int stlink_read_option_bytes_Gx(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to write * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register_f2(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte); +int stlink_read_option_control_register_f2(stlink_t *sl, + uint32_t *option_byte) { + return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte); } /** @@ -3990,8 +4155,8 @@ int stlink_read_option_control_register_f2(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to write * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_option_control_register_f2(sl, option_byte); +int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) { + return stlink_read_option_control_register_f2(sl, option_byte); } /** @@ -4000,8 +4165,9 @@ int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to read * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register_f4(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte); +int stlink_read_option_control_register_f4(stlink_t *sl, + uint32_t *option_byte) { + return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte); } /** @@ -4010,8 +4176,8 @@ int stlink_read_option_control_register_f4(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to read * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_f4(stlink_t *sl, uint32_t* option_byte) { - return stlink_read_option_control_register_f4(sl, option_byte); +int stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) { + return stlink_read_option_control_register_f4(sl, option_byte); } /** @@ -4020,9 +4186,10 @@ int stlink_read_option_bytes_f4(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to read * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register_f7(stlink_t *sl, uint32_t* option_byte) { - DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR); - return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte); +int stlink_read_option_control_register_f7(stlink_t *sl, + uint32_t *option_byte) { + DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR); + return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte); } /** @@ -4031,9 +4198,11 @@ int stlink_read_option_control_register_f7(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to read * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t* option_byte) { - DLOG("@@@@ Read option control register 1 byte from %#10x\n", FLASH_F7_OPTCR1); - return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte); +int stlink_read_option_control_register1_f7(stlink_t *sl, + uint32_t *option_byte) { + DLOG("@@@@ Read option control register 1 byte from %#10x\n", + FLASH_F7_OPTCR1); + return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte); } /** @@ -4042,9 +4211,9 @@ int stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to read * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t* option_byte) { - DLOG("@@@@ Read option byte boot address\n"); - return stlink_read_option_control_register1_f7(sl, option_byte); +int stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) { + DLOG("@@@@ Read option byte boot address\n"); + return stlink_read_option_control_register1_f7(sl, option_byte); } /** @@ -4056,18 +4225,22 @@ int stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t* option_byte) { * Since multiple bytes can be read, we read and print all but one here * and then return the last one just like other devices */ -int stlink_read_option_bytes_f7(stlink_t *sl, uint32_t* option_byte) { - int err = -1; - for (uint8_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) { - err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte); - if (err == -1) { - return err; - } else { - printf("%08x\n", *option_byte); - } +int stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) { + int err = -1; + for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) { + err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), + option_byte); + if (err == -1) { + return err; + } else { + printf("%08x\n", *option_byte); } + } - return stlink_read_debug32(sl, sl->option_base + (uint32_t) (sl->option_size / 4 - 1) * sizeof(uint32_t), option_byte); + return stlink_read_debug32( + sl, + sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t), + option_byte); } /** @@ -4076,9 +4249,9 @@ int stlink_read_option_bytes_f7(stlink_t *sl, uint32_t* option_byte) { * @param option_byte option value * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t* option_byte) { - DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); - return stlink_read_debug32(sl, sl->option_base, option_byte); +int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) { + DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); + return stlink_read_debug32(sl, sl->option_base, option_byte); } /** @@ -4087,7 +4260,8 @@ int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to read * @return 0 on success, -ve on failure. */ -//int stlink_read_option_bytes_boot_add_generic(stlink_t *sl, uint32_t* option_byte) { +// int stlink_read_option_bytes_boot_add_generic(stlink_t *sl, uint32_t* +// option_byte) { // DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); // return stlink_read_debug32(sl, sl->option_base, option_byte); //} @@ -4098,9 +4272,11 @@ int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to read * @return 0 on success, -ve on failure. */ -//int stlink_read_option_control_register_generic(stlink_t *sl, uint32_t* option_byte) { -// DLOG("@@@@ Read option control register byte from %#10x\n", sl->option_base); -// return stlink_read_debug32(sl, sl->option_base, option_byte); +// int stlink_read_option_control_register_generic(stlink_t *sl, uint32_t* +// option_byte) { +// DLOG("@@@@ Read option control register byte from %#10x\n", +// sl->option_base); return stlink_read_debug32(sl, sl->option_base, +// option_byte); //} /** @@ -4109,9 +4285,11 @@ int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t* option_byte) { * @param option_byte value to read * @return 0 on success, -ve on failure. */ -//int stlink_read_option_control_register1_generic(stlink_t *sl, uint32_t* option_byte) { -// DLOG("@@@@ Read option control register 1 byte from %#10x\n", sl->option_base); -// return stlink_read_debug32(sl, sl->option_base, option_byte); +// int stlink_read_option_control_register1_generic(stlink_t *sl, uint32_t* +// option_byte) { +// DLOG("@@@@ Read option control register 1 byte from %#10x\n", +// sl->option_base); return stlink_read_debug32(sl, sl->option_base, +// option_byte); //} /** @@ -4120,28 +4298,28 @@ int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t* option_byte) { * @param option_byte option value * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes32(stlink_t *sl, uint32_t* option_byte) { - if (sl->option_base == 0) { - ELOG("Option bytes read is currently not supported for connected chip\n"); - return(-1); - } - - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F2: - return stlink_read_option_bytes_f2(sl, option_byte); - case STLINK_CHIPID_STM32_F4: - case STLINK_CHIPID_STM32_F446: - return stlink_read_option_bytes_f4(sl, option_byte); - case STLINK_CHIPID_STM32_F7XXXX: - return stlink_read_option_bytes_f7(sl, option_byte); - case STLINK_CHIPID_STM32_G0_CAT1: - case STLINK_CHIPID_STM32_G0_CAT2: - case STLINK_CHIPID_STM32_G4_CAT2: - case STLINK_CHIPID_STM32_G4_CAT3: - return stlink_read_option_bytes_Gx(sl, option_byte); - default: - return stlink_read_option_bytes_generic(sl, option_byte); - } +int stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) { + if (sl->option_base == 0) { + ELOG("Option bytes read is currently not supported for connected chip\n"); + return (-1); + } + + switch (sl->chip_id) { + case STLINK_CHIPID_STM32_F2: + return stlink_read_option_bytes_f2(sl, option_byte); + case STLINK_CHIPID_STM32_F4: + case STLINK_CHIPID_STM32_F446: + return stlink_read_option_bytes_f4(sl, option_byte); + case STLINK_CHIPID_STM32_F7XXXX: + return stlink_read_option_bytes_f7(sl, option_byte); + case STLINK_CHIPID_STM32_G0_CAT1: + case STLINK_CHIPID_STM32_G0_CAT2: + case STLINK_CHIPID_STM32_G4_CAT2: + case STLINK_CHIPID_STM32_G4_CAT3: + return stlink_read_option_bytes_Gx(sl, option_byte); + default: + return stlink_read_option_bytes_generic(sl, option_byte); + } } /** @@ -4150,20 +4328,20 @@ int stlink_read_option_bytes32(stlink_t *sl, uint32_t* option_byte) { * @param option_byte option value * @return 0 on success, -ve on failure. */ -int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t* option_byte) -{ - if (sl->option_base == 0) { - ELOG("Option bytes boot address read is currently not supported for connected chip\n"); - return -1; - } - - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: - return stlink_read_option_bytes_boot_add_f7(sl, option_byte); - default: - return -1; - //return stlink_read_option_bytes_boot_add_generic(sl, option_byte); - } +int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) { + if (sl->option_base == 0) { + ELOG("Option bytes boot address read is currently not supported for " + "connected chip\n"); + return -1; + } + + switch (sl->chip_id) { + case STLINK_CHIPID_STM32_F7XXXX: + return stlink_read_option_bytes_boot_add_f7(sl, option_byte); + default: + return -1; + // return stlink_read_option_bytes_boot_add_generic(sl, option_byte); + } } /** @@ -4172,20 +4350,19 @@ int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t* option_byte) * @param option_byte option value * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register32(stlink_t *sl, uint32_t* option_byte) -{ - if (sl->option_base == 0) { - ELOG("Option bytes read is currently not supported for connected chip\n"); - return -1; - } +int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) { + if (sl->option_base == 0) { + ELOG("Option bytes read is currently not supported for connected chip\n"); + return -1; + } - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: - return stlink_read_option_control_register_f7(sl, option_byte); - default: - return -1; - //return stlink_read_option_control_register_generic(sl, option_byte); - } + switch (sl->chip_id) { + case STLINK_CHIPID_STM32_F7XXXX: + return stlink_read_option_control_register_f7(sl, option_byte); + default: + return -1; + // return stlink_read_option_control_register_generic(sl, option_byte); + } } /** @@ -4194,20 +4371,20 @@ int stlink_read_option_control_register32(stlink_t *sl, uint32_t* option_byte) * @param option_byte option value * @return 0 on success, -ve on failure. */ -int stlink_read_option_control_register1_32(stlink_t *sl, uint32_t* option_byte) -{ - if (sl->option_base == 0) { - ELOG("Option bytes read is currently not supported for connected chip\n"); - return -1; - } - - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: - return stlink_read_option_control_register1_f7(sl, option_byte); - default: - return -1; - //return stlink_read_option_control_register1_generic(sl, option_byte); - } +int stlink_read_option_control_register1_32(stlink_t *sl, + uint32_t *option_byte) { + if (sl->option_base == 0) { + ELOG("Option bytes read is currently not supported for connected chip\n"); + return -1; + } + + switch (sl->chip_id) { + case STLINK_CHIPID_STM32_F7XXXX: + return stlink_read_option_control_register1_f7(sl, option_byte); + default: + return -1; + // return stlink_read_option_control_register1_generic(sl, option_byte); + } } /** @@ -4216,10 +4393,11 @@ int stlink_read_option_control_register1_32(stlink_t *sl, uint32_t* option_byte) * @param option_byte value to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) -{ - WLOG("About to write option byte %#10x to %#10x.\n", option_byte, sl->option_base); - return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *) &option_byte, 4); +int stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) { + WLOG("About to write option byte %#10x to %#10x.\n", option_byte, + sl->option_base); + return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, + 4); } /** @@ -4229,73 +4407,76 @@ int stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) * @param base option bytes to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { - int ret = -1; - - if (sl->option_base == 0) { - ELOG("Option bytes writing is currently not supported for connected chip\n"); - return(-1); - } - - - if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) { - ELOG("Option bytes start address out of Option bytes range\n"); - return(-1); - } - - if (addr + len > sl->option_base + sl->option_size) { - ELOG("Option bytes data too long\n"); - return(-1); - } - - wait_flash_busy(sl); - - if (unlock_flash_if(sl)) { - ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); - return(-1); - } - - if (unlock_flash_option_if(sl)) { - ELOG("Flash option unlock failed!\n"); - return(-1); - } - - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F4: - ret = stlink_write_option_bytes_f4(sl, base, addr, len); - break; - case STLINK_FLASH_TYPE_F7: - ret = stlink_write_option_bytes_f7(sl, base, addr, len); - break; - case STLINK_FLASH_TYPE_L0: - ret = stlink_write_option_bytes_l0(sl, base, addr, len); - break; - case STLINK_FLASH_TYPE_L4: - ret = stlink_write_option_bytes_l4(sl, base, addr, len); - break; - case STLINK_FLASH_TYPE_G0: - case STLINK_FLASH_TYPE_G4: - ret = stlink_write_option_bytes_gx(sl, base, addr, len); - break; - case STLINK_FLASH_TYPE_H7: - ret = stlink_write_option_bytes_h7(sl, base, addr, len); - break; - default: - ELOG("Option bytes writing is currently not implemented for connected chip\n"); - break; - } - - if (ret) { - ELOG("Flash option write failed!\n"); - } else { - ILOG("Wrote %d option bytes to %#010x!\n", len, addr); - } - - /* Re-lock flash. */ - lock_flash_option(sl); - lock_flash(sl); - - return ret; +int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, + uint32_t len) { + int ret = -1; + + if (sl->option_base == 0) { + ELOG( + "Option bytes writing is currently not supported for connected chip\n"); + return (-1); + } + + if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) { + ELOG("Option bytes start address out of Option bytes range\n"); + return (-1); + } + + if (addr + len > sl->option_base + sl->option_size) { + ELOG("Option bytes data too long\n"); + return (-1); + } + + wait_flash_busy(sl); + + if (unlock_flash_if(sl)) { + ELOG("Flash unlock failed! System reset required to be able to unlock it " + "again!\n"); + return (-1); + } + + if (unlock_flash_option_if(sl)) { + ELOG("Flash option unlock failed!\n"); + return (-1); + } + + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F4: + ret = stlink_write_option_bytes_f4(sl, base, addr, len); + break; + case STLINK_FLASH_TYPE_F7: + ret = stlink_write_option_bytes_f7(sl, base, addr, len); + break; + case STLINK_FLASH_TYPE_L0: + ret = stlink_write_option_bytes_l0(sl, base, addr, len); + break; + case STLINK_FLASH_TYPE_L4: + ret = stlink_write_option_bytes_l4(sl, base, addr, len); + break; + case STLINK_FLASH_TYPE_G0: + case STLINK_FLASH_TYPE_G4: + ret = stlink_write_option_bytes_gx(sl, base, addr, len); + break; + case STLINK_FLASH_TYPE_H7: + ret = stlink_write_option_bytes_h7(sl, base, addr, len); + break; + default: + ELOG("Option bytes writing is currently not implemented for connected " + "chip\n"); + break; + } + + if (ret) { + ELOG("Flash option write failed!\n"); + } else { + ILOG("Wrote %d option bytes to %#010x!\n", len, addr); + } + + /* Re-lock flash. */ + lock_flash_option(sl); + lock_flash(sl); + + return ret; } /** @@ -4304,24 +4485,30 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui * @param option_byte value to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_control_register) { - int ret = 0; +static int +stlink_write_option_control_register_f7(stlink_t *sl, + uint32_t option_control_register) { + int ret = 0; - // Clear errors - clear_flash_error(sl); + // Clear errors + clear_flash_error(sl); - ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_control_register, FLASH_F7_OPTCR); + ILOG("Asked to write option control register 1 %#10x to %#010x.\n", + option_control_register, FLASH_F7_OPTCR); - /* write option byte, ensuring we dont lock opt, and set strt bit */ - stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_control_register & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); + /* write option byte, ensuring we dont lock opt, and set strt bit */ + stlink_write_debug32(sl, FLASH_F7_OPTCR, + (option_control_register & ~(1 << FLASH_F7_OPTCR_LOCK)) | + (1 << FLASH_F7_OPTCR_START)); - wait_flash_busy(sl); + wait_flash_busy(sl); - ret = check_flash_error(sl); - if (!ret) - ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register, FLASH_F7_OPTCR); + ret = check_flash_error(sl); + if (!ret) + ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register, + FLASH_F7_OPTCR); - return ret; + return ret; } /** @@ -4330,29 +4517,36 @@ static int stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option * @param option_byte value to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_control_register1) { - int ret = 0; +static int +stlink_write_option_control_register1_f7(stlink_t *sl, + uint32_t option_control_register1) { + int ret = 0; - // Clear errors - clear_flash_error(sl); + // Clear errors + clear_flash_error(sl); - ILOG("Asked to write option control register 1 %#010x to %#010x.\n", option_control_register1, FLASH_F7_OPTCR1); + ILOG("Asked to write option control register 1 %#010x to %#010x.\n", + option_control_register1, FLASH_F7_OPTCR1); - /* write option byte, ensuring we dont lock opt, and set strt bit */ - uint32_t current_control_register_value; - stlink_read_debug32(sl, FLASH_F7_OPTCR, ¤t_control_register_value); + /* write option byte, ensuring we dont lock opt, and set strt bit */ + uint32_t current_control_register_value; + stlink_read_debug32(sl, FLASH_F7_OPTCR, ¤t_control_register_value); - /* write option byte */ - stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_control_register1); - stlink_write_debug32(sl, FLASH_F7_OPTCR, (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); + /* write option byte */ + stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_control_register1); + stlink_write_debug32( + sl, FLASH_F7_OPTCR, + (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) | + (1 << FLASH_F7_OPTCR_START)); - wait_flash_busy(sl); + wait_flash_busy(sl); - ret = check_flash_error(sl); - if (!ret) - ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register1, FLASH_F7_OPTCR1); + ret = check_flash_error(sl); + if (!ret) + ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register1, + FLASH_F7_OPTCR1); - return ret; + return ret; } /** @@ -4361,9 +4555,11 @@ static int stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t optio * @param option_byte value to write * @return 0 on success, -ve on failure. */ -static int stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) { - ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add); - return stlink_write_option_control_register1_f7(sl, option_byte_boot_add); +static int +stlink_write_option_bytes_boot_add_f7(stlink_t *sl, + uint32_t option_byte_boot_add) { + ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add); + return stlink_write_option_control_register1_f7(sl, option_byte_boot_add); } /** @@ -4372,41 +4568,43 @@ static int stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_b * @param option bytes boot address to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) -{ - int ret = -1; +int stlink_write_option_bytes_boot_add32(stlink_t *sl, + uint32_t option_bytes_boot_add) { + int ret = -1; - wait_flash_busy(sl); + wait_flash_busy(sl); - if (unlock_flash_if(sl)) { - ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); - return -1; - } + if (unlock_flash_if(sl)) { + ELOG("Flash unlock failed! System reset required to be able to unlock it " + "again!\n"); + return -1; + } - if (unlock_flash_option_if(sl)) { - ELOG("Flash option unlock failed!\n"); - return -1; - } + if (unlock_flash_option_if(sl)) { + ELOG("Flash option unlock failed!\n"); + return -1; + } - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F7: - ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add); - break; - default: - ELOG("Option bytes boot address writing is currently not implemented for connected chip\n"); - break; - } + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F7: + ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add); + break; + default: + ELOG("Option bytes boot address writing is currently not implemented for " + "connected chip\n"); + break; + } - if (ret) - ELOG("Flash option write failed!\n"); - else - ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add); + if (ret) + ELOG("Flash option write failed!\n"); + else + ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add); - /* Re-lock flash. */ - lock_flash_option(sl); - lock_flash(sl); + /* Re-lock flash. */ + lock_flash_option(sl); + lock_flash(sl); - return ret; + return ret; } /** @@ -4415,41 +4613,43 @@ int stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boo * @param option bytes boot address to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_control_register32(stlink_t *sl, uint32_t option_control_register) -{ - int ret = -1; +int stlink_write_option_control_register32(stlink_t *sl, + uint32_t option_control_register) { + int ret = -1; - wait_flash_busy(sl); + wait_flash_busy(sl); - if (unlock_flash_if(sl)) { - ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); - return -1; - } + if (unlock_flash_if(sl)) { + ELOG("Flash unlock failed! System reset required to be able to unlock it " + "again!\n"); + return -1; + } - if (unlock_flash_option_if(sl)) { - ELOG("Flash option unlock failed!\n"); - return -1; - } + if (unlock_flash_option_if(sl)) { + ELOG("Flash option unlock failed!\n"); + return -1; + } - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F7: - ret = stlink_write_option_control_register_f7(sl, option_control_register); - break; - default: - ELOG("Option control register writing is currently not implemented for connected chip\n"); - break; - } + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F7: + ret = stlink_write_option_control_register_f7(sl, option_control_register); + break; + default: + ELOG("Option control register writing is currently not implemented for " + "connected chip\n"); + break; + } - if (ret) - ELOG("Flash option write failed!\n"); - else - ILOG("Wrote option control register %#010x!\n", option_control_register); + if (ret) + ELOG("Flash option write failed!\n"); + else + ILOG("Wrote option control register %#010x!\n", option_control_register); - /* Re-lock flash. */ - lock_flash_option(sl); - lock_flash(sl); + /* Re-lock flash. */ + lock_flash_option(sl); + lock_flash(sl); - return ret; + return ret; } /** @@ -4458,40 +4658,43 @@ int stlink_write_option_control_register32(stlink_t *sl, uint32_t option_control * @param option bytes boot address to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_control_register1) -{ - int ret = -1; +int stlink_write_option_control_register1_32( + stlink_t *sl, uint32_t option_control_register1) { + int ret = -1; - wait_flash_busy(sl); + wait_flash_busy(sl); - if (unlock_flash_if(sl)) { - ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); - return -1; - } + if (unlock_flash_if(sl)) { + ELOG("Flash unlock failed! System reset required to be able to unlock it " + "again!\n"); + return -1; + } - if (unlock_flash_option_if(sl)) { - ELOG("Flash option unlock failed!\n"); - return -1; - } + if (unlock_flash_option_if(sl)) { + ELOG("Flash option unlock failed!\n"); + return -1; + } - switch (sl->flash_type) { - case STLINK_FLASH_TYPE_F7: - ret = stlink_write_option_control_register1_f7(sl, option_control_register1); - break; - default: - ELOG("Option control register 1 writing is currently not implemented for connected chip\n"); - break; - } + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F7: + ret = + stlink_write_option_control_register1_f7(sl, option_control_register1); + break; + default: + ELOG("Option control register 1 writing is currently not implemented for " + "connected chip\n"); + break; + } - if (ret) - ELOG("Flash option write failed!\n"); - else - ILOG("Wrote option control register 1 %#010x!\n", option_control_register1); + if (ret) + ELOG("Flash option write failed!\n"); + else + ILOG("Wrote option control register 1 %#010x!\n", option_control_register1); - lock_flash_option(sl); - lock_flash(sl); + lock_flash_option(sl); + lock_flash(sl); - return(ret); + return (ret); } /** @@ -4501,61 +4704,66 @@ int stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_contr * @param addr of the memory mapped option bytes * @return 0 on success, -ve on failure. */ -int stlink_fwrite_option_bytes(stlink_t *sl, const char* path, stm32_addr_t addr) { - /* Write the file in flash at addr */ - int err; - mapped_file_t mf = MAPPED_FILE_INITIALIZER; - - if (map_file(&mf, path) == -1) { - ELOG("map_file() == -1\n"); - return(-1); - } +int stlink_fwrite_option_bytes(stlink_t *sl, const char *path, + stm32_addr_t addr) { + /* Write the file in flash at addr */ + int err; + mapped_file_t mf = MAPPED_FILE_INITIALIZER; - printf("file %s ", path); - md5_calculate(&mf); - stlink_checksum(&mf); + if (map_file(&mf, path) == -1) { + ELOG("map_file() == -1\n"); + return (-1); + } - err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len); - stlink_fwrite_finalize(sl, addr); - unmap_file(&mf); + printf("file %s ", path); + md5_calculate(&mf); + stlink_checksum(&mf); - return(err); + err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len); + stlink_fwrite_finalize(sl, addr); + unmap_file(&mf); + + return (err); } int stlink_target_connect(stlink_t *sl, enum connect_type connect) { - uint32_t dhcsr; - - if (connect == CONNECT_UNDER_RESET) { - stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW); + uint32_t dhcsr; - // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) - usleep(20); + if (connect == CONNECT_UNDER_RESET) { + stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW); - if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { stlink_enter_swd_mode(sl); } - stlink_force_debug(sl); + // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) + usleep(20); - // clear S_RESET_ST in DHCSR register - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { + stlink_enter_swd_mode(sl); + } + stlink_force_debug(sl); - stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH); - usleep(10000); + // clear S_RESET_ST in DHCSR register + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - // check NRST connection - dhcsr = 0; - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { - WLOG("NRST is not connected\n"); - } + stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH); + usleep(10000); - // addition soft reset for halt before the first instruction - stlink_soft_reset(sl, 1 /* halt on reset */); + // check NRST connection + dhcsr = 0; + stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { + WLOG("NRST is not connected\n"); } - if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { stlink_enter_swd_mode(sl); } + // addition soft reset for halt before the first instruction + stlink_soft_reset(sl, 1 /* halt on reset */); + } - if (connect == CONNECT_NORMAL) { - stlink_reset(sl, RESET_AUTO); - } + if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { + stlink_enter_swd_mode(sl); + } + + if (connect == CONNECT_NORMAL) { + stlink_reset(sl, RESET_AUTO); + } - return stlink_load_device_params(sl); + return stlink_load_device_params(sl); } diff --git a/src/st-trace/trace.c b/src/st-trace/trace.c index f28624475..a02c64701 100644 --- a/src/st-trace/trace.c +++ b/src/st-trace/trace.c @@ -1,556 +1,596 @@ +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include #include +#include -#include -#include #include - +#include +#include #define DEFAULT_LOGGING_LEVEL 50 #define DEBUG_LOGGING_LEVEL 100 -#define APP_RESULT_SUCCESS 0 -#define APP_RESULT_INVALID_PARAMS 1 -#define APP_RESULT_STLINK_NOT_FOUND 2 -#define APP_RESULT_STLINK_MISSING_DEVICE 3 -#define APP_RESULT_STLINK_UNSUPPORTED_DEVICE 4 -#define APP_RESULT_STLINK_UNSUPPORTED_LINK 5 -#define APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY 6 -#define APP_RESULT_STLINK_STATE_ERROR 7 +#define APP_RESULT_SUCCESS 0 +#define APP_RESULT_INVALID_PARAMS 1 +#define APP_RESULT_STLINK_NOT_FOUND 2 +#define APP_RESULT_STLINK_MISSING_DEVICE 3 +#define APP_RESULT_STLINK_UNSUPPORTED_DEVICE 4 +#define APP_RESULT_STLINK_UNSUPPORTED_LINK 5 +#define APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY 6 +#define APP_RESULT_STLINK_STATE_ERROR 7 // See D4.2 of https://developer.arm.com/documentation/ddi0403/ed/ -#define TRACE_OP_IS_OVERFLOW(c) ((c) == 0x70) -#define TRACE_OP_IS_LOCAL_TIME(c) (((c) & 0x0f) == 0x00 && ((c) & 0x70) != 0x00) -#define TRACE_OP_IS_EXTENSION(c) (((c) & 0x0b) == 0x08) -#define TRACE_OP_IS_GLOBAL_TIME(c) (((c) & 0xdf) == 0x94) -#define TRACE_OP_IS_SOURCE(c) (((c) & 0x03) != 0x00) -#define TRACE_OP_IS_SW_SOURCE(c) (((c) & 0x03) != 0x00 && ((c) & 0x04) == 0x00) -#define TRACE_OP_IS_HW_SOURCE(c) (((c) & 0x03) != 0x00 && ((c) & 0x04) == 0x04) -#define TRACE_OP_IS_TARGET_SOURCE(c) ((c) == 0x01) -#define TRACE_OP_GET_CONTINUATION(c) ((c) & 0x80) -#define TRACE_OP_GET_SOURCE_SIZE(c) ((c) & 0x03) -#define TRACE_OP_GET_SW_SOURCE_ADDR(c) ((c) >> 3) - +#define TRACE_OP_IS_OVERFLOW(c) ((c) == 0x70) +#define TRACE_OP_IS_LOCAL_TIME(c) (((c)&0x0f) == 0x00 && ((c)&0x70) != 0x00) +#define TRACE_OP_IS_EXTENSION(c) (((c)&0x0b) == 0x08) +#define TRACE_OP_IS_GLOBAL_TIME(c) (((c)&0xdf) == 0x94) +#define TRACE_OP_IS_SOURCE(c) (((c)&0x03) != 0x00) +#define TRACE_OP_IS_SW_SOURCE(c) (((c)&0x03) != 0x00 && ((c)&0x04) == 0x00) +#define TRACE_OP_IS_HW_SOURCE(c) (((c)&0x03) != 0x00 && ((c)&0x04) == 0x04) +#define TRACE_OP_IS_TARGET_SOURCE(c) ((c) == 0x01) +#define TRACE_OP_GET_CONTINUATION(c) ((c)&0x80) +#define TRACE_OP_GET_SOURCE_SIZE(c) ((c)&0x03) +#define TRACE_OP_GET_SW_SOURCE_ADDR(c) ((c) >> 3) typedef struct { - bool show_help; - bool show_version; - int logging_level; - uint32_t core_frequency; - uint32_t trace_frequency; - bool reset_board; - bool force; - char* serial_number; + bool show_help; + bool show_version; + int logging_level; + uint32_t core_frequency; + uint32_t trace_frequency; + bool reset_board; + bool force; + char *serial_number; } st_settings_t; - // We use a simple state machine to parse the trace data. typedef enum { - TRACE_STATE_UNKNOWN, - TRACE_STATE_IDLE, - TRACE_STATE_TARGET_SOURCE, - TRACE_STATE_SKIP_FRAME, - TRACE_STATE_SKIP_4, - TRACE_STATE_SKIP_3, - TRACE_STATE_SKIP_2, - TRACE_STATE_SKIP_1, + TRACE_STATE_UNKNOWN, + TRACE_STATE_IDLE, + TRACE_STATE_TARGET_SOURCE, + TRACE_STATE_SKIP_FRAME, + TRACE_STATE_SKIP_4, + TRACE_STATE_SKIP_3, + TRACE_STATE_SKIP_2, + TRACE_STATE_SKIP_1, } trace_state; typedef struct { - time_t start_time; - bool configuration_checked; + time_t start_time; + bool configuration_checked; - trace_state state; + trace_state state; - uint32_t count_raw_bytes; - uint32_t count_target_data; - uint32_t count_time_packets; - uint32_t count_hw_overflow; - uint32_t count_sw_overflow; - uint32_t count_error; + uint32_t count_raw_bytes; + uint32_t count_target_data; + uint32_t count_time_packets; + uint32_t count_hw_overflow; + uint32_t count_sw_overflow; + uint32_t count_error; - uint8_t unknown_opcodes[256 / 8]; - uint32_t unknown_sources; + uint8_t unknown_opcodes[256 / 8]; + uint32_t unknown_sources; } st_trace_t; - -// We use a global flag to allow communicating to the main thread from the signal handler. +// We use a global flag to allow communicating to the main thread from the +// signal handler. static bool g_abort_trace = false; -static void abort_trace() { - g_abort_trace = true; -} +static void abort_trace() { g_abort_trace = true; } #if defined(_WIN32) BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { - (void)fdwCtrlType; - abort_trace(); - return FALSE; + (void)fdwCtrlType; + abort_trace(); + return FALSE; } #endif static void usage(void) { - puts("st-trace - usage:"); - puts(" -h, --help Print this help"); - puts(" -V, --version Print this version"); - puts(" -vXX, --verbose=XX Specify a specific verbosity level (0..99)"); - puts(" -v, --verbose Specify a generally verbose logging"); - puts(" -cXX, --clock=XX Specify the core frequency in MHz"); - puts(" -tXX, --trace=XX Specify the trace frequency in Hz"); - puts(" -n, --no-reset Do not reset board on connection"); - puts(" -sXX, --serial=XX Use a specific serial number"); - puts(" -f, --force Ignore most initialization errors"); + puts("st-trace - usage:"); + puts(" -h, --help Print this help"); + puts(" -V, --version Print this version"); + puts(" -vXX, --verbose=XX Specify a specific verbosity level (0..99)"); + puts(" -v, --verbose Specify a generally verbose logging"); + puts(" -cXX, --clock=XX Specify the core frequency in MHz"); + puts(" -tXX, --trace=XX Specify the trace frequency in Hz"); + puts(" -n, --no-reset Do not reset board on connection"); + puts(" -sXX, --serial=XX Use a specific serial number"); + puts(" -f, --force Ignore most initialization errors"); } -bool parse_options(int argc, char** argv, st_settings_t *settings) { - - static struct option long_options[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {"verbose", optional_argument, NULL, 'v'}, - {"clock", required_argument, NULL, 'c'}, - {"trace", required_argument, NULL, 't'}, - {"no-reset", no_argument, NULL, 'n'}, - {"serial", required_argument, NULL, 's'}, - {"force", no_argument, NULL, 'f'}, - {0, 0, 0, 0}, - }; - int option_index = 0; - int c; - bool error = false; - - settings->show_help = false; - settings->show_version = false; - settings->logging_level = DEFAULT_LOGGING_LEVEL; - settings->core_frequency = 0; - settings->trace_frequency = 0; - settings->reset_board = true; - settings->force = false; - settings->serial_number = NULL; - ugly_init(settings->logging_level); - - while ((c = getopt_long(argc, argv, "hVv::c:ns:f", long_options, &option_index)) != -1) { - switch (c) { - case 'h': - settings->show_help = true; - break; - case 'V': - settings->show_version = true; - break; - case 'v': - if (optarg) { - settings->logging_level = atoi(optarg); - } else { - settings->logging_level = DEBUG_LOGGING_LEVEL; - } - ugly_init(settings->logging_level); - break; - case 'c': - settings->core_frequency = atoi(optarg) * 1000000; - break; - case 't': - settings->trace_frequency = atoi(optarg); - break; - case 'n': - settings->reset_board = false; - break; - case 'f': - settings->force = true; - break; - case 's': - settings->serial_number = optarg; - break; - case '?': - error = true; - break; - default: - ELOG("Unknown command line option: '%c' (0x%02x)\n", c, c); - error = true; - break; - } +bool parse_options(int argc, char **argv, st_settings_t *settings) { + + static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {"verbose", optional_argument, NULL, 'v'}, + {"clock", required_argument, NULL, 'c'}, + {"trace", required_argument, NULL, 't'}, + {"no-reset", no_argument, NULL, 'n'}, + {"serial", required_argument, NULL, 's'}, + {"force", no_argument, NULL, 'f'}, + {0, 0, 0, 0}, + }; + int option_index = 0; + int c; + bool error = false; + + settings->show_help = false; + settings->show_version = false; + settings->logging_level = DEFAULT_LOGGING_LEVEL; + settings->core_frequency = 0; + settings->trace_frequency = 0; + settings->reset_board = true; + settings->force = false; + settings->serial_number = NULL; + ugly_init(settings->logging_level); + + while ((c = getopt_long(argc, argv, "hVv::c:ns:f", long_options, + &option_index)) != -1) { + switch (c) { + case 'h': + settings->show_help = true; + break; + case 'V': + settings->show_version = true; + break; + case 'v': + if (optarg) { + settings->logging_level = atoi(optarg); + } else { + settings->logging_level = DEBUG_LOGGING_LEVEL; + } + ugly_init(settings->logging_level); + break; + case 'c': + settings->core_frequency = atoi(optarg) * 1000000; + break; + case 't': + settings->trace_frequency = atoi(optarg); + break; + case 'n': + settings->reset_board = false; + break; + case 'f': + settings->force = true; + break; + case 's': + settings->serial_number = optarg; + break; + case '?': + error = true; + break; + default: + ELOG("Unknown command line option: '%c' (0x%02x)\n", c, c); + error = true; + break; } + } - if (optind < argc) { - while (optind < argc) { - ELOG("Unknown command line argument: '%s'\n", argv[optind++]); - } - error = true; + if (optind < argc) { + while (optind < argc) { + ELOG("Unknown command line argument: '%s'\n", argv[optind++]); } + error = true; + } - if (error && !settings->force) - return false; + if (error && !settings->force) + return false; - return true; + return true; } -static stlink_t* stlink_connect(const st_settings_t* settings) { - return stlink_open_usb(settings->logging_level, false, settings->serial_number, 0); +static stlink_t *stlink_connect(const st_settings_t *settings) { + return stlink_open_usb(settings->logging_level, false, + settings->serial_number, 0); } -static bool enable_trace(stlink_t* stlink, const st_settings_t* settings, uint32_t trace_frequency) { - - if (stlink_force_debug(stlink)) { - ELOG("Unable to debug device\n"); - if (!settings->force) - return false; - } - - if (settings->reset_board && stlink_reset(stlink, RESET_AUTO)) { - ELOG("Unable to reset device\n"); - if (!settings->force) - return false; - } - - - stlink_write_debug32(stlink, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | - STLINK_REG_DHCSR_C_DEBUGEN | - STLINK_REG_DHCSR_C_HALT); - stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); - stlink_write_debug32(stlink, STLINK_REG_CM3_FP_CTRL, STLINK_REG_CM3_FP_CTRL_KEY); - stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION0, 0); - stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION1, 0); - stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION2, 0); - stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION3, 0); - stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 0); - stlink_write_debug32(stlink, STLINK_REG_DBGMCU_CR, STLINK_REG_DBGMCU_CR_DBG_SLEEP | - STLINK_REG_DBGMCU_CR_DBG_STOP | - STLINK_REG_DBGMCU_CR_DBG_STANDBY | - STLINK_REG_DBGMCU_CR_TRACE_IOEN | - STLINK_REG_DBGMCU_CR_TRACE_MODE_ASYNC); - - if (stlink_trace_enable(stlink, trace_frequency)) { - ELOG("Unable to turn on tracing in stlink\n"); - if (!settings->force) - return false; - } - - stlink_write_debug32(stlink, STLINK_REG_TPI_CSPSR, STLINK_REG_TPI_CSPSR_PORT_SIZE_1); - - if (settings->core_frequency) { - uint32_t prescaler = settings->core_frequency / trace_frequency - 1; - if (prescaler > STLINK_REG_TPI_ACPR_MAX) { - ELOG("Trace frequency prescaler %d out of range. Try setting a faster trace frequency.\n", prescaler); - if (!settings->force) - return false; - } - stlink_write_debug32(stlink, STLINK_REG_TPI_ACPR, prescaler); // Set TPIU_ACPR clock divisor - } - stlink_write_debug32(stlink, STLINK_REG_TPI_FFCR, STLINK_REG_TPI_FFCR_TRIG_IN); - stlink_write_debug32(stlink, STLINK_REG_TPI_SPPR, STLINK_REG_TPI_SPPR_SWO_NRZ); - stlink_write_debug32(stlink, STLINK_REG_ITM_LAR, STLINK_REG_ITM_LAR_KEY); - stlink_write_debug32(stlink, STLINK_REG_ITM_TCC, 0x00000400); // Set sync counter - stlink_write_debug32(stlink, STLINK_REG_ITM_TCR, STLINK_REG_ITM_TCR_TRACE_BUS_ID_1 | - STLINK_REG_ITM_TCR_TS_ENA | - STLINK_REG_ITM_TCR_ITM_ENA); - stlink_write_debug32(stlink, STLINK_REG_ITM_TER, STLINK_REG_ITM_TER_PORTS_ALL); - stlink_write_debug32(stlink, STLINK_REG_ITM_TPR, STLINK_REG_ITM_TPR_PORTS_ALL); - stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 4 * STLINK_REG_DWT_CTRL_NUM_COMP | - STLINK_REG_DWT_CTRL_CYC_TAP | - 0xF * STLINK_REG_DWT_CTRL_POST_INIT | - 0xF * STLINK_REG_DWT_CTRL_POST_PRESET | - STLINK_REG_DWT_CTRL_CYCCNT_ENA); - stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); - - uint32_t prescaler; - stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR_MAX, &prescaler); - if (prescaler) { - uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; - uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000; - ILOG("Trace Port Interface configured to expect a %d MHz system clock.\n", system_clock_speed_mhz); - } else { - WLOG("Trace Port Interface not configured. Specify the system clock with a --clock=XX command\n"); - WLOG("line option or set it in your device's clock initialization routine, such as with:\n"); - WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); +static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, + uint32_t trace_frequency) { + + if (stlink_force_debug(stlink)) { + ELOG("Unable to debug device\n"); + if (!settings->force) + return false; + } + + if (settings->reset_board && stlink_reset(stlink, RESET_AUTO)) { + ELOG("Unable to reset device\n"); + if (!settings->force) + return false; + } + + stlink_write_debug32(stlink, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + STLINK_REG_DHCSR_C_HALT); + stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); + stlink_write_debug32(stlink, STLINK_REG_CM3_FP_CTRL, + STLINK_REG_CM3_FP_CTRL_KEY); + stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION0, 0); + stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION1, 0); + stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION2, 0); + stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION3, 0); + stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 0); + stlink_write_debug32( + stlink, STLINK_REG_DBGMCU_CR, + STLINK_REG_DBGMCU_CR_DBG_SLEEP | STLINK_REG_DBGMCU_CR_DBG_STOP | + STLINK_REG_DBGMCU_CR_DBG_STANDBY | STLINK_REG_DBGMCU_CR_TRACE_IOEN | + STLINK_REG_DBGMCU_CR_TRACE_MODE_ASYNC); + + if (stlink_trace_enable(stlink, trace_frequency)) { + ELOG("Unable to turn on tracing in stlink\n"); + if (!settings->force) + return false; + } + + stlink_write_debug32(stlink, STLINK_REG_TPI_CSPSR, + STLINK_REG_TPI_CSPSR_PORT_SIZE_1); + + if (settings->core_frequency) { + uint32_t prescaler = settings->core_frequency / trace_frequency - 1; + if (prescaler > STLINK_REG_TPI_ACPR_MAX) { + ELOG("Trace frequency prescaler %d out of range. Try setting a faster " + "trace frequency.\n", + prescaler); + if (!settings->force) + return false; } - ILOG("Trace frequency set to %d Hz.\n", trace_frequency); - - return true; + stlink_write_debug32(stlink, STLINK_REG_TPI_ACPR, + prescaler); // Set TPIU_ACPR clock divisor + } + stlink_write_debug32(stlink, STLINK_REG_TPI_FFCR, + STLINK_REG_TPI_FFCR_TRIG_IN); + stlink_write_debug32(stlink, STLINK_REG_TPI_SPPR, + STLINK_REG_TPI_SPPR_SWO_NRZ); + stlink_write_debug32(stlink, STLINK_REG_ITM_LAR, STLINK_REG_ITM_LAR_KEY); + stlink_write_debug32(stlink, STLINK_REG_ITM_TCC, + 0x00000400); // Set sync counter + stlink_write_debug32(stlink, STLINK_REG_ITM_TCR, + STLINK_REG_ITM_TCR_TRACE_BUS_ID_1 | + STLINK_REG_ITM_TCR_TS_ENA | + STLINK_REG_ITM_TCR_ITM_ENA); + stlink_write_debug32(stlink, STLINK_REG_ITM_TER, + STLINK_REG_ITM_TER_PORTS_ALL); + stlink_write_debug32(stlink, STLINK_REG_ITM_TPR, + STLINK_REG_ITM_TPR_PORTS_ALL); + stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, + 4 * STLINK_REG_DWT_CTRL_NUM_COMP | + STLINK_REG_DWT_CTRL_CYC_TAP | + 0xF * STLINK_REG_DWT_CTRL_POST_INIT | + 0xF * STLINK_REG_DWT_CTRL_POST_PRESET | + STLINK_REG_DWT_CTRL_CYCCNT_ENA); + stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); + + uint32_t prescaler; + stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR_MAX, &prescaler); + if (prescaler) { + uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; + uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000; + ILOG("Trace Port Interface configured to expect a %d MHz system clock.\n", + system_clock_speed_mhz); + } else { + WLOG("Trace Port Interface not configured. Specify the system clock with " + "a --clock=XX command\n"); + WLOG("line option or set it in your device's clock initialization routine, " + "such as with:\n"); + WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); + } + ILOG("Trace frequency set to %d Hz.\n", trace_frequency); + + return true; } -static trace_state update_trace_idle(st_trace_t* trace, uint8_t c) { - // Handle a trace byte when we are in the idle state. - - if (TRACE_OP_IS_TARGET_SOURCE(c)) { - return TRACE_STATE_TARGET_SOURCE; - } - - if (TRACE_OP_IS_SOURCE(c)) { - uint8_t size = TRACE_OP_GET_SOURCE_SIZE(c); - if (TRACE_OP_IS_SW_SOURCE(c)) { - uint8_t addr = TRACE_OP_GET_SW_SOURCE_ADDR(c); - if (!(trace->unknown_sources & (1 << addr))) - WLOG("Unsupported source 0x%x size %d\n", addr, size); - trace->unknown_sources |= (1 << addr); - } - if (size == 1) return TRACE_STATE_SKIP_1; - if (size == 2) return TRACE_STATE_SKIP_2; - if (size == 3) return TRACE_STATE_SKIP_4; - } - - if (TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) { - trace->count_time_packets++; - return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; - } - - if (TRACE_OP_IS_EXTENSION(c)) { - return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; - } - - if (TRACE_OP_IS_OVERFLOW(c)) { - trace->count_hw_overflow++; - } - - if (!(trace->unknown_opcodes[c / 8] & (1 << c % 8))) - WLOG("Unknown opcode 0x%02x\n", c); - trace->unknown_opcodes[c / 8] |= (1 << c % 8); - - trace->count_error++; - return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; +static trace_state update_trace_idle(st_trace_t *trace, uint8_t c) { + // Handle a trace byte when we are in the idle state. + + if (TRACE_OP_IS_TARGET_SOURCE(c)) { + return TRACE_STATE_TARGET_SOURCE; + } + + if (TRACE_OP_IS_SOURCE(c)) { + uint8_t size = TRACE_OP_GET_SOURCE_SIZE(c); + if (TRACE_OP_IS_SW_SOURCE(c)) { + uint8_t addr = TRACE_OP_GET_SW_SOURCE_ADDR(c); + if (!(trace->unknown_sources & (1 << addr))) + WLOG("Unsupported source 0x%x size %d\n", addr, size); + trace->unknown_sources |= (1 << addr); + } + if (size == 1) + return TRACE_STATE_SKIP_1; + if (size == 2) + return TRACE_STATE_SKIP_2; + if (size == 3) + return TRACE_STATE_SKIP_4; + } + + if (TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) { + trace->count_time_packets++; + return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME + : TRACE_STATE_IDLE; + } + + if (TRACE_OP_IS_EXTENSION(c)) { + return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME + : TRACE_STATE_IDLE; + } + + if (TRACE_OP_IS_OVERFLOW(c)) { + trace->count_hw_overflow++; + } + + if (!(trace->unknown_opcodes[c / 8] & (1 << c % 8))) + WLOG("Unknown opcode 0x%02x\n", c); + trace->unknown_opcodes[c / 8] |= (1 << c % 8); + + trace->count_error++; + return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME + : TRACE_STATE_IDLE; } -static trace_state update_trace(st_trace_t* trace, uint8_t c) { - trace->count_raw_bytes++; +static trace_state update_trace(st_trace_t *trace, uint8_t c) { + trace->count_raw_bytes++; - // Parse the input using a state machine. + // Parse the input using a state machine. - if (trace->state == TRACE_STATE_UNKNOWN) { - if (TRACE_OP_IS_TARGET_SOURCE(c) || TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) - trace->state = TRACE_STATE_IDLE; - } + if (trace->state == TRACE_STATE_UNKNOWN) { + if (TRACE_OP_IS_TARGET_SOURCE(c) || TRACE_OP_IS_LOCAL_TIME(c) || + TRACE_OP_IS_GLOBAL_TIME(c)) + trace->state = TRACE_STATE_IDLE; + } - switch (trace->state) - { - case TRACE_STATE_IDLE: - return update_trace_idle(trace, c); + switch (trace->state) { + case TRACE_STATE_IDLE: + return update_trace_idle(trace, c); - case TRACE_STATE_TARGET_SOURCE: - putchar(c); - if (c == '\n') - fflush(stdout); - trace->count_target_data++; - return TRACE_STATE_IDLE; + case TRACE_STATE_TARGET_SOURCE: + putchar(c); + if (c == '\n') + fflush(stdout); + trace->count_target_data++; + return TRACE_STATE_IDLE; - case TRACE_STATE_SKIP_FRAME: - return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; + case TRACE_STATE_SKIP_FRAME: + return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME + : TRACE_STATE_IDLE; - case TRACE_STATE_SKIP_4: - return TRACE_STATE_SKIP_3; + case TRACE_STATE_SKIP_4: + return TRACE_STATE_SKIP_3; - case TRACE_STATE_SKIP_3: - return TRACE_STATE_SKIP_2; + case TRACE_STATE_SKIP_3: + return TRACE_STATE_SKIP_2; - case TRACE_STATE_SKIP_2: - return TRACE_STATE_SKIP_1; + case TRACE_STATE_SKIP_2: + return TRACE_STATE_SKIP_1; - case TRACE_STATE_SKIP_1: - return TRACE_STATE_IDLE; + case TRACE_STATE_SKIP_1: + return TRACE_STATE_IDLE; - case TRACE_STATE_UNKNOWN: - return TRACE_STATE_UNKNOWN; + case TRACE_STATE_UNKNOWN: + return TRACE_STATE_UNKNOWN; - default: - ELOG("Invalid state %d. This should never happen\n", trace->state); - return TRACE_STATE_IDLE; - } + default: + ELOG("Invalid state %d. This should never happen\n", trace->state); + return TRACE_STATE_IDLE; + } } -static bool read_trace(stlink_t* stlink, st_trace_t* trace) { - uint8_t buffer[STLINK_TRACE_BUF_LEN]; - int length = stlink_trace_read(stlink, buffer, sizeof(buffer)); - - if (length < 0) { - ELOG("Error reading trace (%d)\n", length); - return false; - } - - if (length == 0) { - usleep(100); - return true; - } - - if (length == sizeof(buffer)) { - if (trace->count_sw_overflow++) - DLOG("Buffer overflow.\n"); - else - WLOG("Buffer overflow. Try using a slower trace frequency.\n"); - trace->state = TRACE_STATE_UNKNOWN; - } +static bool read_trace(stlink_t *stlink, st_trace_t *trace) { + uint8_t buffer[STLINK_TRACE_BUF_LEN]; + int length = stlink_trace_read(stlink, buffer, sizeof(buffer)); - for (int i = 0; i < length; i++) { - trace->state = update_trace(trace, buffer[i]); - } + if (length < 0) { + ELOG("Error reading trace (%d)\n", length); + return false; + } + if (length == 0) { + usleep(100); return true; -} - -static void check_for_configuration_error(stlink_t* stlink, st_trace_t* trace, uint32_t trace_frequency) { - // Only check configuration one time after the first 10 seconds of running. - time_t elapsed_time_s = time(NULL) - trace->start_time; - if (trace->configuration_checked || elapsed_time_s < 10) { - return; - } - trace->configuration_checked = true; + } - // Simple huristic to determine if we are configured poorly. - bool error_no_data = (trace->count_raw_bytes < 100); - bool error_low_data = (trace->count_time_packets < 10 && trace->count_target_data < 1000); - bool error_bad_data = (trace->count_error > 1 || trace->unknown_sources > 0); - bool error_dropped_data = (trace->count_sw_overflow > 0); + if (length == sizeof(buffer)) { + if (trace->count_sw_overflow++) + DLOG("Buffer overflow.\n"); + else + WLOG("Buffer overflow. Try using a slower trace frequency.\n"); + trace->state = TRACE_STATE_UNKNOWN; + } - if (!error_no_data && !error_low_data && !error_bad_data && !error_dropped_data) - return; - - WLOG("****\n"); - WLOG("We do not appear to be retrieving data from the stlink correctly.\n"); - - if (error_dropped_data) { - WLOG("Try setting a slower trace frequency with the --trace=%d command line option.\n", trace_frequency / 2); - } + for (int i = 0; i < length; i++) { + trace->state = update_trace(trace, buffer[i]); + } - if (error_no_data || error_low_data || error_bad_data) { - uint32_t prescaler; - stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR, &prescaler); - if (prescaler) { - uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; - uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000; - WLOG("Verify the system clock is running at %d MHz.\n", system_clock_speed_mhz); - } - WLOG("Try specifying the system clock with the --clock=XX command line option.\n"); - WLOG("Try setting the trace speed in your device's clock initialization routine:\n"); - WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); - } + return true; +} - WLOG("Diagnostic Information:\n"); - WLOG("Raw Bytes: %d\n", trace->count_raw_bytes); - WLOG("Target Data: %d\n", trace->count_target_data); - WLOG("Time Packets: %d\n", trace->count_time_packets); - WLOG("Hardware Overflow Count: %d\n", trace->count_hw_overflow); - WLOG("Software Overflow Count: %d\n", trace->count_sw_overflow); - WLOG("Errors: %d\n", trace->count_error); - - char buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - uint32_t offset = 0; - for (uint32_t i = 0; i <= 0xFF; i++) - if (trace->unknown_opcodes[i / 8] & (1 << i % 8)) - offset += snprintf(buffer + offset, sizeof(buffer) - offset, "%02x, ", i); - WLOG("Unknown Opcodes: %s\n", buffer); - - memset(buffer, 0, sizeof(buffer)); - offset = 0; - for (uint32_t i = 0; i < 32; i++) - if (trace->unknown_sources & (1 << i)) - offset += snprintf(buffer + offset, sizeof(buffer) - offset, "%d, ", i); - WLOG("Unknown Sources: %s\n", buffer); - - WLOG("Chip ID: 0x%04x\n", stlink->chip_id); - WLOG("****\n"); +static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, + uint32_t trace_frequency) { + // Only check configuration one time after the first 10 seconds of running. + time_t elapsed_time_s = time(NULL) - trace->start_time; + if (trace->configuration_checked || elapsed_time_s < 10) { + return; + } + trace->configuration_checked = true; + + // Simple huristic to determine if we are configured poorly. + bool error_no_data = (trace->count_raw_bytes < 100); + bool error_low_data = + (trace->count_time_packets < 10 && trace->count_target_data < 1000); + bool error_bad_data = (trace->count_error > 1 || trace->unknown_sources > 0); + bool error_dropped_data = (trace->count_sw_overflow > 0); + + if (!error_no_data && !error_low_data && !error_bad_data && + !error_dropped_data) + return; + + WLOG("****\n"); + WLOG("We do not appear to be retrieving data from the stlink correctly.\n"); + + if (error_dropped_data) { + WLOG("Try setting a slower trace frequency with the --trace=%d command " + "line option.\n", + trace_frequency / 2); + } + + if (error_no_data || error_low_data || error_bad_data) { + uint32_t prescaler; + stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR, &prescaler); + if (prescaler) { + uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; + uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000; + WLOG("Verify the system clock is running at %d MHz.\n", + system_clock_speed_mhz); + } + WLOG("Try specifying the system clock with the --clock=XX command line " + "option.\n"); + WLOG("Try setting the trace speed in your device's clock initialization " + "routine:\n"); + WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); + } + + WLOG("Diagnostic Information:\n"); + WLOG("Raw Bytes: %d\n", trace->count_raw_bytes); + WLOG("Target Data: %d\n", trace->count_target_data); + WLOG("Time Packets: %d\n", trace->count_time_packets); + WLOG("Hardware Overflow Count: %d\n", trace->count_hw_overflow); + WLOG("Software Overflow Count: %d\n", trace->count_sw_overflow); + WLOG("Errors: %d\n", trace->count_error); + + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + uint32_t offset = 0; + for (uint32_t i = 0; i <= 0xFF; i++) + if (trace->unknown_opcodes[i / 8] & (1 << i % 8)) { + uint32_t n = + snprintf(buffer + offset, sizeof(buffer) - offset, "%02x, ", i); + if (n >= sizeof(buffer) - offset) { + break; + } + offset += n; + } + WLOG("Unknown Opcodes: %s\n", buffer); + + memset(buffer, 0, sizeof(buffer)); + offset = 0; + for (uint32_t i = 0; i < 32; i++) + if (trace->unknown_sources & (1 << i)) { + uint32_t n = + snprintf(buffer + offset, sizeof(buffer) - offset, "%d, ", i); + if (n >= sizeof(buffer) - offset) { + break; + } + offset += n; + } + WLOG("Unknown Sources: %s\n", buffer); + + WLOG("Chip ID: 0x%04x\n", stlink->chip_id); + WLOG("****\n"); } -int main(int argc, char** argv) -{ +int main(int argc, char **argv) { #if defined(_WIN32) - SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); + SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); #else - signal(SIGINT, &abort_trace); - signal(SIGTERM, &abort_trace); - signal(SIGSEGV, &abort_trace); - signal(SIGPIPE, &abort_trace); + signal(SIGINT, &abort_trace); + signal(SIGTERM, &abort_trace); + signal(SIGSEGV, &abort_trace); + signal(SIGPIPE, &abort_trace); #endif + st_settings_t settings; + if (!parse_options(argc, argv, &settings)) { + usage(); + return APP_RESULT_INVALID_PARAMS; + } + + DLOG("show_help = %s\n", settings.show_help ? "true" : "false"); + DLOG("show_version = %s\n", settings.show_version ? "true" : "false"); + DLOG("logging_level = %d\n", settings.logging_level); + DLOG("core_frequency = %d Hz\n", settings.core_frequency); + DLOG("trace_frequency = %d Hz\n", settings.trace_frequency); + DLOG("reset_board = %s\n", settings.reset_board ? "true" : "false"); + DLOG("force = %s\n", settings.force ? "true" : "false"); + DLOG("serial_number = %s\n", + settings.serial_number ? settings.serial_number : "any"); + + if (settings.show_help) { + usage(); + return APP_RESULT_SUCCESS; + } - st_settings_t settings; - if (!parse_options(argc, argv, &settings)) { - usage(); - return APP_RESULT_INVALID_PARAMS; - } - - DLOG("show_help = %s\n", settings.show_help ? "true" : "false"); - DLOG("show_version = %s\n", settings.show_version ? "true" : "false"); - DLOG("logging_level = %d\n", settings.logging_level); - DLOG("core_frequency = %d Hz\n", settings.core_frequency); - DLOG("trace_frequency = %d Hz\n", settings.trace_frequency); - DLOG("reset_board = %s\n", settings.reset_board ? "true" : "false"); - DLOG("force = %s\n", settings.force ? "true" : "false"); - DLOG("serial_number = %s\n", settings.serial_number ? settings.serial_number : "any"); - - if (settings.show_help) { - usage(); - return APP_RESULT_SUCCESS; - } - - if (settings.show_version) { - printf("v%s\n", STLINK_VERSION); - return APP_RESULT_SUCCESS; - } - - stlink_t* stlink = stlink_connect(&settings); - if (!stlink) { - ELOG("Unable to locate an stlink\n"); - return APP_RESULT_STLINK_NOT_FOUND; - } - - stlink->verbose = settings.logging_level; - - if (stlink->chip_id == STLINK_CHIPID_UNKNOWN) { - ELOG("Your stlink is not connected to a device\n"); - if (!settings.force) - return APP_RESULT_STLINK_MISSING_DEVICE; - } - - if (!(stlink->version.flags & STLINK_F_HAS_TRACE)) { - ELOG("Your stlink does not support tracing\n"); - if (!settings.force) - return APP_RESULT_STLINK_UNSUPPORTED_LINK; - } - - if (!(stlink->chip_flags & CHIP_F_HAS_SWO_TRACING)) { - const struct stlink_chipid_params *params = stlink_chipid_get_params(stlink->chip_id); - ELOG("We do not support SWO output for device '%s'\n", params->description); - if (!settings.force) - return APP_RESULT_STLINK_UNSUPPORTED_DEVICE; - } - - uint32_t trace_frequency = settings.trace_frequency; - if (!trace_frequency) - trace_frequency = STLINK_DEFAULT_TRACE_FREQUENCY; - if (trace_frequency > stlink->max_trace_freq) { - ELOG("Invalid trace frequency %d (max %d)\n", trace_frequency, stlink->max_trace_freq); - if (!settings.force) - return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY; - } - - if (!enable_trace(stlink, &settings, trace_frequency)) { - ELOG("Unable to enable trace mode\n"); - if (!settings.force) - return APP_RESULT_STLINK_STATE_ERROR; - } - - ILOG("Reading Trace\n"); - st_trace_t trace; - memset(&trace, 0, sizeof(trace)); - trace.start_time = time(NULL); - - if (stlink_run(stlink, RUN_NORMAL)) { - ELOG("Unable to run device\n"); - if (!settings.force) - return APP_RESULT_STLINK_STATE_ERROR; - } - - while (!g_abort_trace && read_trace(stlink, &trace)) { - check_for_configuration_error(stlink, &trace, trace_frequency); - } - - stlink_trace_disable(stlink); - stlink_close(stlink); - + if (settings.show_version) { + printf("v%s\n", STLINK_VERSION); return APP_RESULT_SUCCESS; + } + + stlink_t *stlink = stlink_connect(&settings); + if (!stlink) { + ELOG("Unable to locate an stlink\n"); + return APP_RESULT_STLINK_NOT_FOUND; + } + + stlink->verbose = settings.logging_level; + + if (stlink->chip_id == STLINK_CHIPID_UNKNOWN) { + ELOG("Your stlink is not connected to a device\n"); + if (!settings.force) + return APP_RESULT_STLINK_MISSING_DEVICE; + } + + if (!(stlink->version.flags & STLINK_F_HAS_TRACE)) { + ELOG("Your stlink does not support tracing\n"); + if (!settings.force) + return APP_RESULT_STLINK_UNSUPPORTED_LINK; + } + + if (!(stlink->chip_flags & CHIP_F_HAS_SWO_TRACING)) { + const struct stlink_chipid_params *params = + stlink_chipid_get_params(stlink->chip_id); + ELOG("We do not support SWO output for device '%s'\n", params->description); + if (!settings.force) + return APP_RESULT_STLINK_UNSUPPORTED_DEVICE; + } + + uint32_t trace_frequency = settings.trace_frequency; + if (!trace_frequency) + trace_frequency = STLINK_DEFAULT_TRACE_FREQUENCY; + if (trace_frequency > stlink->max_trace_freq) { + ELOG("Invalid trace frequency %d (max %d)\n", trace_frequency, + stlink->max_trace_freq); + if (!settings.force) + return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY; + } + + if (!enable_trace(stlink, &settings, trace_frequency)) { + ELOG("Unable to enable trace mode\n"); + if (!settings.force) + return APP_RESULT_STLINK_STATE_ERROR; + } + + ILOG("Reading Trace\n"); + st_trace_t trace; + memset(&trace, 0, sizeof(trace)); + trace.start_time = time(NULL); + + if (stlink_run(stlink, RUN_NORMAL)) { + ELOG("Unable to run device\n"); + if (!settings.force) + return APP_RESULT_STLINK_STATE_ERROR; + } + + while (!g_abort_trace && read_trace(stlink, &trace)) { + check_for_configuration_error(stlink, &trace, trace_frequency); + } + + stlink_trace_disable(stlink); + stlink_close(stlink); + + return APP_RESULT_SUCCESS; } diff --git a/src/stlink-lib/logging.c b/src/stlink-lib/logging.c index ce0a2baab..87978230d 100644 --- a/src/stlink-lib/logging.c +++ b/src/stlink-lib/logging.c @@ -1,12 +1,13 @@ /* * UglyLogging * - * Slow, yet another wheel reinvented, but enough to make the rest of our code pretty enough. + * Slow, yet another wheel reinvented, but enough to make the rest of our code + * pretty enough. */ +#include #include #include #include -#include #include #include "logging.h" @@ -14,77 +15,89 @@ static int max_level = UDEBUG; int ugly_init(int maximum_threshold) { - max_level = maximum_threshold; - return(0); + max_level = maximum_threshold; + return (0); } int ugly_log(int level, const char *tag, const char *format, ...) { - if (level > max_level) { - return(0); - } + if (level > max_level) { + return (0); + } - fflush(stdout); // flush to maintain order of streams + fflush(stdout); // flush to maintain order of streams - va_list args; - va_start(args, format); - time_t mytt = time(NULL); - struct tm *tt; - tt = localtime(&mytt); - fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, tt->tm_mon + 1, - tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec); + va_list args; + va_start(args, format); + time_t mytt = time(NULL); + struct tm *tt; + tt = localtime(&mytt); + fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, + tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec); - switch (level) { - case UDEBUG: - fprintf(stderr, "DEBUG %s: ", tag); - break; - case UINFO: - fprintf(stderr, "INFO %s: ", tag); - break; - case UWARN: - fprintf(stderr, "WARN %s: ", tag); - break; - case UERROR: - fprintf(stderr, "ERROR %s: ", tag); - break; - default: - fprintf(stderr, "%d %s: ", level, tag); - break; - } + switch (level) { + case UDEBUG: + fprintf(stderr, "DEBUG %s: ", tag); + break; + case UINFO: + fprintf(stderr, "INFO %s: ", tag); + break; + case UWARN: + fprintf(stderr, "WARN %s: ", tag); + break; + case UERROR: + fprintf(stderr, "ERROR %s: ", tag); + break; + default: + fprintf(stderr, "%d %s: ", level, tag); + break; + } - vfprintf(stderr, format, args); - fflush(stderr); - va_end(args); - return(1); + vfprintf(stderr, format, args); + fflush(stderr); + va_end(args); + return (1); } /* * Log message levels. - * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) + * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library + * (default) * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr - * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr + * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to + * stderr + * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to + * stderr + * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are + * printed to stderr */ int ugly_libusb_log_level(enum ugly_loglevel v) { #ifdef __FreeBSD__ - // FreeBSD includes its own reimplementation of libusb. - // Its libusb_set_debug() function expects a lib_debug_level - // instead of a lib_log_level and is verbose enough to drown out - // all other output. - switch (v) { - case UDEBUG: return (3); // LIBUSB_DEBUG_FUNCTION + LIBUSB_DEBUG_TRANSFER - case UINFO: return (1); // LIBUSB_DEBUG_FUNCTION only - case UWARN: return (0); // LIBUSB_DEBUG_NO - case UERROR: return (0); // LIBUSB_DEBUG_NO - } - return (0); + // FreeBSD includes its own reimplementation of libusb. + // Its libusb_set_debug() function expects a lib_debug_level + // instead of a lib_log_level and is verbose enough to drown out + // all other output. + switch (v) { + case UDEBUG: + return (3); // LIBUSB_DEBUG_FUNCTION + LIBUSB_DEBUG_TRANSFER + case UINFO: + return (1); // LIBUSB_DEBUG_FUNCTION only + case UWARN: + return (0); // LIBUSB_DEBUG_NO + case UERROR: + return (0); // LIBUSB_DEBUG_NO + } + return (0); #else - switch (v) { - case UDEBUG: return (4); - case UINFO: return (3); - case UWARN: return (2); - case UERROR: return (1); - } + switch (v) { + case UDEBUG: + return (4); + case UINFO: + return (3); + case UWARN: return (2); + case UERROR: + return (1); + } + return (2); #endif }