/**
******************************************************************************
* @file aiTestUtility.c
* @author MCD Vertical Application Team
* @brief STM32 Utility functions for STM32 AI test application
******************************************************************************
* @attention
*
*
© Copyright (c) YYYY STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/*
* Description:
*
*
* History:
* - v1.0 - initial version (from initial aiSystemPerformance file - v5.1)
* - v1.1 - add Arm Compiler 6 support (MDK)
* - v2.0 - add io low level code to manage a COM through the STM32 USB CDC profile
* enabled with the USE_USB_CDC_CLASS define.
*
*/
#include
#include
#include
#define USE_USB_CDC_CLASS
/* -----------------------------------------------------------------------------
* Sanity check
* -----------------------------------------------------------------------------
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
#elif defined(__ICCARM__)
#if _APP_HEAP_MONITOR_ == 1
#undef _APP_HEAP_MONITOR_
#define _APP_HEAP_MONITOR_ 0
#error HEAP monitor is not YET supported
#endif
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
#if _APP_STACK_MONITOR_ == 1
#undef _APP_STACK_MONITOR_
#define _APP_STACK_MONITOR_ 0
#error STACK monitor is not YET supported
#endif
#if _APP_HEAP_MONITOR_ == 1
#undef _APP_HEAP_MONITOR_
#define _APP_HEAP_MONITOR_ 0
#error HEAP monitor is not YET supported
#endif
#else
#error ARM MCU tool chain is not supported
#endif
/* -----------------------------------------------------------------------------
* IO functions
* -----------------------------------------------------------------------------
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
#include
#include /* STDOUT_FILENO, STDERR_FILENO */
#elif defined (__ICCARM__)
#if (__IAR_SYSTEMS_ICC__ <= 8)
/* Temporary workaround - LowLevelIOInterface.h seems not available
with IAR 7.80.4 */
#define _LLIO_STDIN 0
#define _LLIO_STDOUT 1
#define _LLIO_STDERR 2
#define _LLIO_ERROR ((size_t)-1) /* For __read and __write. */
#else
#include /* _LLIO_STDOUT, _LLIO_STDERR */
#endif
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
#endif
#if defined(USE_USB_CDC_CLASS)
#include "usbd_cdc_if.h"
#define _MAX_USB_USER_ELEM (128)
uint8_t _usb_fifo[_MAX_USB_USER_ELEM];
volatile uint32_t _usb_nb_w_item = 0;
volatile uint32_t _usb_nb_r_item = 0;
uint8_t *_usb_p_read = &_usb_fifo[0];
uint8_t *_usb_p_write = &_usb_fifo[0];
#endif
extern UART_HandleTypeDef UartHandle;
static bool _ioWriteAllowed = true;
int ioRawGetUint8(uint8_t *c, uint32_t timeout)
{
HAL_StatusTypeDef status;
if (!c)
return -1;
status = HAL_UART_Receive(&UartHandle, (uint8_t *)c, 1,
timeout);
if (status == HAL_TIMEOUT)
return -1;
return (status == HAL_OK ? 1 : 0);
}
#if defined(USE_USB_CDC_CLASS)
void ioPushInUserUsb(uint8_t *pw, uint32_t *len)
{
uint8_t *pr = pw;
for (int i=0; i < *len; i++) {
*_usb_p_write++ = *pr++;
if (_usb_p_write == &_usb_fifo[_MAX_USB_USER_ELEM])
_usb_p_write = &_usb_fifo[0];
_usb_nb_w_item++;
}
}
bool ioRawWriteBuffer(uint8_t *buff, int count)
{
HAL_StatusTypeDef status = HAL_OK;
while (USBD_BUSY == CDC_Transmit_FS(buff, count));
return (status == HAL_OK);
}
bool ioRawReadBuffer(uint8_t *buff, int count)
{
HAL_StatusTypeDef status = HAL_OK;
while ((_usb_nb_w_item - _usb_nb_r_item) < count) {};
uint8_t *pw = buff;
for (int i=0; i < count; i++) {
*pw++ = *_usb_p_read++;
if (_usb_p_read == &_usb_fifo[_MAX_USB_USER_ELEM])
_usb_p_read = &_usb_fifo[0];
_usb_nb_r_item++;
}
return (status == HAL_OK);
}
void ioRawDisableLLWrite(void)
{
}
#else
bool ioRawWriteBuffer(uint8_t *buff, int count)
{
HAL_StatusTypeDef status;
status = HAL_UART_Transmit(&UartHandle, buff, count, HAL_MAX_DELAY);
return (status == HAL_OK);
}
bool ioRawReadBuffer(uint8_t *buff, int count)
{
HAL_StatusTypeDef status;
status = HAL_UART_Receive(&UartHandle, buff, count, HAL_MAX_DELAY);
return (status == HAL_OK);
}
void ioRawDisableLLWrite(void)
{
_ioWriteAllowed = false;
}
#endif
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
int _write(int fd, const void *buff, int count);
int _write(int fd, const void *buff, int count)
{
HAL_StatusTypeDef status;
if ((count < 0) && (fd != STDOUT_FILENO) && (fd != STDERR_FILENO)) {
errno = EBADF;
return -1;
}
if (_ioWriteAllowed)
status = HAL_UART_Transmit(&UartHandle, (uint8_t *)buff, count,
HAL_MAX_DELAY);
else
status = HAL_OK;
return (status == HAL_OK ? count : 0);
}
#elif defined (__ICCARM__)
__ATTRIBUTES size_t __write(int handle, const unsigned char *buffer,
size_t size);
__ATTRIBUTES size_t __write(int handle, const unsigned char *buffer,
size_t size)
{
HAL_StatusTypeDef status;
/*
* This means that we should flush internal buffers. Since we
* don't we just return. (Remember, "handle" == -1 means that all
* handles should be flushed.)
*/
if (buffer == 0)
return 0;
/* This template only writes to "standard out" and "standard err",
* for all other file handles it returns failure.
*/
if ((handle != _LLIO_STDOUT) && (handle != _LLIO_STDERR))
return _LLIO_ERROR;
if (_ioWriteAllowed)
status = HAL_UART_Transmit(&UartHandle, (uint8_t *)buffer, size,
HAL_MAX_DELAY);
else
status = HAL_OK;
return (status == HAL_OK ? size : _LLIO_ERROR);
}
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
int fputc(int ch, FILE *f)
{
if (_ioWriteAllowed)
HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1,
HAL_MAX_DELAY);
return ch;
}
#else
#error ARM MCU tool-chain is not supported.
#endif
/* -----------------------------------------------------------------------------
* HEAP Monitor functions
* -----------------------------------------------------------------------------
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
#define MAGIC_MALLOC_NUMBER 0xefdcba98
struct io_malloc io_malloc;
void* __real_malloc(size_t bytes);
void __real_free(void *ptr);
void* __wrap_malloc(size_t bytes)
{
uint8_t *ptr;
io_malloc.cfg |= 1 << 1;
/* ensure alignment for magic number */
bytes = (bytes + 3) & ~3;
/* add 2x32-bit for size and magic number */
ptr = (uint8_t*)__real_malloc(bytes + 8);
/* remember size */
if (ptr) {
*((uint32_t*)ptr) = bytes;
*((uint32_t*)(ptr + 4 + bytes)) = MAGIC_MALLOC_NUMBER;
}
if ((ptr) && (io_malloc.cfg & 1UL)) {
io_malloc.alloc_req++;
io_malloc.alloc += bytes;
io_malloc.used += bytes;
if (io_malloc.used > io_malloc.max) {
io_malloc.max = io_malloc.used;
}
#if _IO_MALLOC_TRACK_MODE == 1
io_malloc.a_ptr[io_malloc.a_idx] = (ptr + 4);
io_malloc.a_s[io_malloc.a_idx] = bytes;
io_malloc.a_idx++;
if (io_malloc.a_idx >= _IO_MALLOC_TRACK_MODE)
io_malloc.a_idx = 0;
#endif
}
return ptr?(ptr + 4):NULL;
}
void __wrap_free(void *ptr)
{
uint8_t* p;
uint32_t bytes;
io_malloc.cfg |= 1 << 2;
if (!ptr)
return;
p = (uint8_t*)ptr - 4;
bytes = *((uint32_t*)p);
if (*((uint32_t*)(p + 4 + bytes)) == MAGIC_MALLOC_NUMBER) {
*((uint32_t*)(p + 4 + bytes)) = 0;
}
if (io_malloc.cfg & 1UL) {
io_malloc.free_req++;
io_malloc.free += bytes;
io_malloc.used -= bytes;
#if _IO_MALLOC_TRACK_MODE == 1
io_malloc.f_ptr[io_malloc.f_idx] = ptr;
io_malloc.f_s[io_malloc.f_idx] = bytes;
io_malloc.f_idx++;
if (io_malloc.f_idx >= _IO_MALLOC_TRACK_MODE)
io_malloc.f_idx = 0;
#endif
}
__real_free(p);
}
#endif
/* -----------------------------------------------------------------------------
* STACK Monitor functions
* -----------------------------------------------------------------------------
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
extern uint32_t _estack[];
#elif defined (__ICCARM__)
extern int CSTACK$$Limit;
extern int CSTACK$$Base;
#endif
struct io_stack io_stack;
void stackMonInit(uint32_t ctrl, uint32_t cstack, uint32_t msize)
{
memset(&io_stack, 0, sizeof(struct io_stack));
/* Reading ARM Core registers */
io_stack.ctrl = ctrl;
io_stack.cstack = cstack;
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
io_stack.estack = (uint32_t)_estack;
io_stack.bstack = io_stack.estack - msize;
io_stack.mstack_size = msize;
#elif defined (__ICCARM__)
io_stack.estack = (uint32_t)&CSTACK$$Limit;
io_stack.bstack = (uint32_t)&CSTACK$$Base;
io_stack.mstack_size = (uint32_t)&CSTACK$$Limit - (uint32_t)&CSTACK$$Base;
#endif
/* Check that MSP is the active stack */
if (io_stack.ctrl & CONTROL_SPSEL_Msk) {
printf("E: MSP is not the active stack (stack monitoring is disabled)\r\n");
io_stack.stack_mon = false;
} else
io_stack.stack_mon = true;
/* Calculating used stack before test */
io_stack.ustack_size = io_stack.estack - io_stack.cstack;
if ((io_stack.stack_mon) && (io_stack.ustack_size > io_stack.mstack_size)) {
printf("E: !stack overflow detected %d > %d\r\n", (int)io_stack.ustack_size,
(int)io_stack.mstack_size);
io_stack.stack_mon = false;
}
}
/* -----------------------------------------------------------------------------
* HW-setting functions
* -----------------------------------------------------------------------------
*/
struct cyclesCount cyclesCount;
__STATIC_INLINE void crcIpInit(void)
{
#if defined(STM32H7)
/* By default the CRC IP clock is enabled */
__HAL_RCC_CRC_CLK_ENABLE();
#elif defined(STM32MP1)
__HAL_RCC_CRC2_CLK_ENABLE();
#else
if (!__HAL_RCC_CRC_IS_CLK_ENABLED())
printf("W: CRC IP clock is NOT enabled\r\n");
/* By default the CRC IP clock is enabled */
__HAL_RCC_CRC_CLK_ENABLE();
#endif
}
void dwtIpInit(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#ifdef STM32F7
DWT->LAR = 0xC5ACCE55;
#endif
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk | DWT_CTRL_CPIEVTENA_Msk;
}
uint32_t systemCoreClock(void)
{
#if defined(STM32MP1)
return HAL_RCC_GetSystemCoreClockFreq();
#elif !defined(STM32H7)
return HAL_RCC_GetHCLKFreq();
#else
return HAL_RCC_GetSysClockFreq();
#endif
}
int dwtCyclesToTime(uint64_t clks, struct dwtTime *t)
{
if (!t)
return -1;
uint32_t fcpu = systemCoreClock();
uint64_t s = clks / fcpu;
uint64_t ms = (clks * 1000) / fcpu;
uint64_t us = (clks * 1000 * 1000) / fcpu;
ms -= (s * 1000);
us -= (ms * 1000 + s * 1000000);
t->fcpu = fcpu;
t->s = s;
t->ms = ms;
t->us = us;
return 0;
}
float dwtCyclesToFloatMs(uint64_t clks)
{
float res;
float fcpu = (float)systemCoreClock();
res = ((float)clks * (float)1000.0) / fcpu;
return res;
}
__STATIC_INLINE const char *devIdToStr(uint16_t dev_id)
{
/* DEV_ID field from DBGMCU register */
const char *str;
switch (dev_id) {
case 0x422: str = "STM32F303xB/C"; break;
case 0x438: str = "STM32F303x6/8"; break;
case 0x446: str = "STM32F303xD/E"; break;
case 0x431: str = "STM32F411xC/E"; break;
case 0x423: str = "STM32F401xB/C"; break;
case 0x433: str = "STM32F401xD/E"; break;
case 0x435: str = "STM32L43xxx"; break;
case 0x462: str = "STM32L45xxx"; break;
case 0x415: str = "STM32L4x6xx"; break;
case 0x470: str = "STM32L4Rxxx"; break;
case 0x472: str = "STM32L5[5,6]2xx"; break;
case 0x449: str = "STM32F74xxx"; break;
case 0x450: str = "STM32H743/53/50xx and STM32H745/55/47/57xx"; break; /* see RM0433 & RM0399 */
case 0x451: str = "STM32F7[6,7]xxx"; break; /* see RM0410 */
default: str = "UNKNOWN";
}
return str;
}
#if !defined(STM32F3) && !defined(STM32MP1)
__STATIC_INLINE const char* bitToStr(uint32_t val)
{
if (val)
return "True";
else
return "False";
}
#endif
static uint32_t mconf;
uint32_t getFlashCacheConf(void)
{
return mconf;
}
void systemSettingLog(void)
{
struct dwtTime t;
uint32_t st;
#if !defined(STM32F3) && !defined(STM32L5)
uint32_t acr = FLASH->ACR ;
#endif
uint32_t val;
/* Display ARM Complier version */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
printf("Compiled with MDK-ARM Keil (Arm Compiler 6) %d\r\n", __ARMCC_VERSION);
#elif defined(__GNUC__)
printf("Compiled with GCC %d.%d.%d\r\n", __GNUC__, __GNUC_MINOR__,
__GNUC_PATCHLEVEL__);
#elif defined(__ICCARM__)
printf("Compiled with IAR %d (build %d)\r\n", __IAR_SYSTEMS_ICC__,
__BUILD_NUMBER__
);
#elif defined (__CC_ARM)
printf("Compiled with MDK-ARM Keil %d\r\n", __ARMCC_VERSION);
#endif
/* Display Device configuration */
printf("STM32 Runtime configuration...\r\n");
printf(" Device : DevID:0x%04x (%s) RevID:0x%04x\r\n",
(int)HAL_GetDEVID(),
devIdToStr(HAL_GetDEVID()),
(int)HAL_GetREVID()
);
printf(" Core Arch. : M%d - %s %s\r\n",
__CORTEX_M,
#if (__FPU_PRESENT == 1)
"FPU PRESENT",
__FPU_USED ? "and used" : "and not used!"
#else
"!FPU NOT PRESENT",
""
#endif
);
#if (__FPU_PRESENT == 1) && __FPU_USED
mconf = (1 << 16); /* FPU present and used */
#endif
printf(" HAL version : 0x%08x\r\n", (int)HAL_GetHalVersion());
val = systemCoreClock()/1000000;
#if !defined(STM32H7)
printf(" system clock : %u MHz\r\n", (int)val);
#else
printf(" SYSCLK clock : %u MHz\r\n", (int)val);
printf(" HCLK clock : %u MHz\r\n", (int)HAL_RCC_GetHCLKFreq()/1000000);
#endif
#if defined(STM32F7) || defined(STM32H7)
val = SCB->CCR;
#if !defined(STM32H7)
mconf |= (2 << 24); /* F7 conf. */
mconf |= ((acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos);
if ((acr & FLASH_ACR_PRFTEN_Msk) >> FLASH_ACR_PRFTEN_Pos)
mconf |= (1 << 8);
if ((acr & FLASH_ACR_ARTEN_Msk) >> FLASH_ACR_ARTEN_Pos)
mconf |= (1 << 9);
printf(" FLASH conf. : ACR=0x%08x - Prefetch=%s ART=%s latency=%d\r\n",
(int)acr,
bitToStr((acr & FLASH_ACR_PRFTEN_Msk) >> FLASH_ACR_PRFTEN_Pos),
bitToStr((acr & FLASH_ACR_ARTEN_Msk) >> FLASH_ACR_ARTEN_Pos),
(int)((acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos));
#else
mconf |= (3 << 24); /* H7 conf. */
mconf |= (acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos;
printf(" FLASH conf. : ACR=0x%08x - latency=%d\r\n",
(int)acr,
(int)((acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos));
#endif
#if !defined(CORE_M4)
if (val & SCB_CCR_IC_Msk)
mconf |= (1 << 10);
if (val & SCB_CCR_DC_Msk)
mconf |= (1 << 11);
printf(" CACHE conf. : $I/$D=(%s,%s)\r\n",
bitToStr(val & SCB_CCR_IC_Msk),
bitToStr(val & SCB_CCR_DC_Msk));
#endif
#else
#if !defined(STM32F3) && !defined(STM32L5) && !defined(STM32MP1)
mconf |= (1 << 24); /* F4/L4 conf. */
mconf |= ((acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos);
if ((acr & FLASH_ACR_PRFTEN_Msk) >> FLASH_ACR_PRFTEN_Pos)
mconf |= (1 << 8);
if ((acr & FLASH_ACR_ICEN_Msk) >> FLASH_ACR_ICEN_Pos)
mconf |= (1 << 9);
if ((acr & FLASH_ACR_DCEN_Msk) >> FLASH_ACR_DCEN_Pos)
mconf |= (1 << 10);
printf(" FLASH conf. : ACR=0x%08x - Prefetch=%s $I/$D=(%s,%s) latency=%d\r\n",
(int)acr,
bitToStr((acr & FLASH_ACR_PRFTEN_Msk) >> FLASH_ACR_PRFTEN_Pos),
bitToStr((acr & FLASH_ACR_ICEN_Msk) >> FLASH_ACR_ICEN_Pos),
bitToStr((acr & FLASH_ACR_DCEN_Msk) >> FLASH_ACR_DCEN_Pos),
(int)((acr & FLASH_ACR_LATENCY_Msk) >> FLASH_ACR_LATENCY_Pos));
#endif
#if defined(STM32L5)
printf(" ICACHE : %s\r\n", bitToStr(READ_BIT(ICACHE->CR, ICACHE_CR_EN)));
#endif
#endif
/* Init CRC and DWT */
crcIpInit();
dwtIpInit();
/* Display HAL tick Calibration */
dwtReset();
HAL_Delay(100);
st = dwtGetCycles();
dwtCyclesToTime(st/100, &t);
printf(" Calibration : HAL_Delay(1)=%d.%03d ms\r\n",
t.s * 100 + t.ms, t.us);
}