А как вам мимикрия, вроде STM32FEBK вместо STM32F103?
После подпаивания сброса OpenOCD его видит как 103.
$ whois arterychip.com
Domain Name: ARTERYCHIP.COM
Registry Domain ID: 2572664777_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.godaddy.com
Registrar URL: http://www.godaddy.com
Updated Date: 2024-08-28T09:02:48Z
Creation Date: 2020-11-16T07:16:34Z
если нужно один в один, то следует брать stm32, полагаю это очевидно даже ребенкуЯ все-таки подожду честных отзывов. И если окажется, что прямо вообще один-в-один
Ну так выше было сказано, что "артери" - прямо точный клон STM32 по прошивке…если нужно один в один, то следует брать stm32
Код: Выделить всё
/opt/openocd_at32/bin/openocd-at32 -s "/opt/openocd-at32/share/openocd/scripts" -f interface/stlink.cfg -f target/at32f403axx.cfg -c "init" -c "reset halt" -c "flash write_image erase blink.bin 0x08000000" -c "reset" -c "exit"У H5 не OTG, а HOST, как у G0 и младших U5, но это буквально пару лишних бит поверх старого USB, правда там есть и другие отличия, для примера:linux_rulezz писал(а):Да исследовать более детально G и H серии, особенно последнюю (правда, там вроде как USB OTG - т.е. все равно придется переделывать USB-сниппет): вдруг там есть что-то интересное
Код: Выделить всё
#if defined(STM32G0) || defined(STM32H5)
static void writePma(uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
auto pVal = (volatile uint32_t*)(USB_DRD_PMAADDR + pmaBufAddr);
for (uint32_t words = length / 4; words != 0; words--)
{
*pVal++ = unalignedRead<uint32_t>(buf);
buf += 4;
}
if (uint32_t bytes = length % 4; bytes != 0)
{
uint32_t val = 0;
buf += bytes;
while (bytes--)
{
val = (val << 8) | *(--buf);
}
*pVal = val;
}
}
#else
static void writePma(const uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
static constexpr uint32_t pmaAccess = sizeof(PmaWidth) / 2;
auto pVal = (volatile uint16_t*)(USB_PMAADDR + pmaBufAddr * pmaAccess);
for (uint32_t i = (length + 1) / 2; i != 0; i--)
{
*pVal = buf[0] | (buf[1] << 8);
buf += 2;
pVal += pmaAccess;
}
}
#endifЕсли соотношение ОЗУ/ПЗУ изменяется, то увы и ах. Хотя флэш всегда честная, правда доступ к ней идёт с двумя циклами ожидания вместо доступа без ожидания, когда код находится в той части флэш, которая не отобразилась на ОЗУ, но это так, мелочи, написанные в сноске мелкими буковками. И всю расчудесную производительность эти МК демонстрируют при исполнении кода из ОЗУ.HardWareMan писал(а):Если у Артерий честная флешка на кристалле, то это только в плюс.
вроде бы выходит, что можно взять проект от F030 и минимальными правками адаптировать его для F421. я пошел чуть другим путем и дописал в стиле CMSIS (китайцы почему-то от него отказались) необходимые дифайны, оставив китайские названия регистров:По AT32F421k8T7 как замена STM32F030K6T6
Запаяли образцы в наши изделия.
Программатор ST-LINKv2 (и ПО ST-Link Utility) с ними отказался работать , т.к. ID-CODE в регистрах DUBUG модуля имеет другое значение или расположен по другому адресу (для СМ0).
Пришлось применять программатор AT-LINK и ПО этого программатора.
Заливка готовой прошивки (.нех файла ) от проекта для STM показала неработоспособность нашей прошивки для STM
Изучение RM (reference manual) показало, что некоторые модули совсем или неполно совместимы с регистрами модулей STM. ЭТО
USART, ADC, SPI. Базовые адреса модулей и вектора прерываний те же, а регистры модулей отличаются. Для SPI всё совпадает кроме 16 битного режима.
В USART AT нет регистра и прерывания по таймауту (применялся для обнаружения конца MODBUS пакетов) Пришлось для этой цели задействовать дополнительный таймер.
Совпадают (или имеют несущественные для наших проектов- помечены*) следующие модули:
GPIO* - отличия в OSPEEDR – у АТ нет скорости M- средней. У STM 00=L; 01=M; 11=H У AT 00=L; 01=H; 11=L. Для нас несущественно
RCC*- У АТ есть больше значений для управлениями частотами PLL до 300Мгц. В пределах 48 Мгц всё совпадает. Поэтому стартовая функция CMSIS system_stm32f0xx.c для STM работает штатно в АТ.
SYSCFG* (CR1 bits 0&1) управление переносом таблицы прерываний в STM (CM0) пишется и читается. В АТ(СМ4)- только читается. Перенос в АТ возможен через SCB_VTOR (есть в СМ4 и нет в СМ0). Управление EXTI полностью совпадает.
SysTick, NVIC, WDT, TIM3, TIM6,Tim7, TIM14, TIM16, TIM17- отличий не нашел (не пришлось что-то менять в проекте для STM32F030K6T6).
Ядро СМ4, включая системный таймер и прерывания работает с прошивкой для СМ0 без нареканий.
Если в проекте не применяются USART, ADC, SPI (16 битный режим) то возможно прошивка для STM заработает на АТ без доработки (прошивать правда придется родным АТ-Link или J-Link программаторами)
Удалось у АТ найти недокументированную возможность для определения при старте прошивки где она работает? В STM или АТ? Далее запоминаем где работаем и при работе с USART, ADC, SPI работаем с регистрами STM или AT. В Результате удалось разработать универсальную прошивку для наших изделий, которая работает одинаково с AT32F421k8T7 и STM32F030K6T6. Компилировался универсальный проект в KEIL CMSIS (без CUBE и HAL) для STM32F030. Для работы с регистрами АТ создал .h файл описания регистров и битов для АТ USART_AT, ADC_AT, SPI_AT.
Недокументированную возможность следующая:
ID-CODE в СМ4 читается в регистре которого нет в СМ0. DEBUG_IDCODE (адрес 0xE0042000) . Чтение в СМ0 приведет к ошибке.
У СМ0 ID-code читается в DBGMCU->IDCODE (адрес 0x40015800), Для STM030 значение с маcкой 0xfff равно 0x444. Этот адрес в доке у АТ написан как резервный, Но реально там читается без ошибки копия адреса 0xE0042000, те тот же ID_CODE.
Код: Выделить всё
/**
* AT32F421 CRM (Clock and Reset Management) Configuration
*
* Purpose: Configure AT32F421 CRM module for system clock and peripheral clocks
* Features: Supports both internal HICK and external HEXT crystal sources
* Performance: Optimized with Flash prefetch buffers and auto-step mode
* Usage: Define HEXT_FREQUENCY (4,8,12,16,20,25) for external crystal or leave
* undefined to use internal 4MHz HICK oscillator
*
* Configuration Options:
* • HICK (default): 4MHz × 30 = 120MHz
* • HEXT 4MHz: 4MHz × 30 = 120MHz
* • HEXT 8MHz: 8MHz × 15 = 120MHz
* • HEXT 12MHz: 12MHz × 10 = 120MHz
* • HEXT 16MHz: 16MHz/2 × 15 = 120MHz
* • HEXT 20MHz: 20MHz/2 × 12 = 120MHz
* • HEXT 25MHz: 25MHz/2 × 10 = 125MHz (Warning: Not exactly 120MHz)
*
* Key Features:
* ✓ System clock configuration (up to 120MHz)
* ✓ Single function to enable all used peripheral clocks
* ✓ Automatic PLL multiplication calculation
* ✓ Flash wait cycles optimized for high frequency
* ✓ Dual prefetch buffers enabled for maximum performance
* ✓ Auto-step mode for smooth clock transitions
* ✓ Robust timeout handling for all clock operations
* ✓ Compile-time configuration validation
* ✓ Centralized system clock definitions for all modules
*
* Example Usage:
* #define HEXT_FREQUENCY 8 // Use 8MHz external crystal
* crm_config(); // Configure system clock and enable peripheral clocks
*/
#ifndef CRM_H
#define CRM_H
#include "at32f421.h"
/* Configuration macro - define external crystal frequency to use HEXT */
// #define HEXT_FREQUENCY 8 // External crystal frequency in MHz (uncomment to use HEXT)
/* Timeout values for clock operations - avoid naming conflicts with HAL */
#define CRM_HEXT_TIMEOUT 50000U
#define CRM_PLL_TIMEOUT 50000U
#define CRM_SWITCH_TIMEOUT 50000U
/*******************************************************************************
* System Clock Definitions - Single Source of Truth
******************************************************************************/
/* System clock frequency - depends on crystal configuration */
#if defined(HEXT_FREQUENCY) && (HEXT_FREQUENCY == 25)
#define SYSTEM_CLOCK_HZ 125000000U /* 25MHz crystal case */
#else
#define SYSTEM_CLOCK_HZ 120000000U /* All other cases: HICK, 4/8/12/16/20MHz crystals */
#endif
/* Derived bus frequencies (all running at system clock speed) */
#define AHB_CLOCK_HZ SYSTEM_CLOCK_HZ
#define APB1_CLOCK_HZ SYSTEM_CLOCK_HZ
#define APB2_CLOCK_HZ SYSTEM_CLOCK_HZ
/* Peripheral clock sources for modules to use */
#define TIMER_CLOCK_HZ APB1_CLOCK_HZ
#define USART1_CLOCK_HZ APB2_CLOCK_HZ
#define GPIO_CLOCK_HZ AHB_CLOCK_HZ
/*******************************************************************************
* CRM CFG Register Bit Definitions
******************************************************************************/
/* System Clock Selection */
#define CRM_CFG_SCLKSEL_Pos 0
#define CRM_CFG_SCLKSEL_Msk (0x3U << CRM_CFG_SCLKSEL_Pos)
#define CRM_CFG_SCLKSEL_HICK (0x0U << CRM_CFG_SCLKSEL_Pos)
#define CRM_CFG_SCLKSEL_HEXT (0x1U << CRM_CFG_SCLKSEL_Pos)
#define CRM_CFG_SCLKSEL_PLL (0x2U << CRM_CFG_SCLKSEL_Pos)
/* System Clock Status */
#define CRM_CFG_SCLKSTS_Pos 2
#define CRM_CFG_SCLKSTS_Msk (0x3U << CRM_CFG_SCLKSTS_Pos)
#define CRM_CFG_SCLKSTS_PLL (0x2U << CRM_CFG_SCLKSTS_Pos)
/* AHB Clock Divider */
#define CRM_CFG_AHBDIV_Pos 4
#define CRM_CFG_AHBDIV_Msk (0xFU << CRM_CFG_AHBDIV_Pos)
#define CRM_CFG_AHBDIV_1 (0x0U << CRM_CFG_AHBDIV_Pos)
/* APB1 Clock Divider */
#define CRM_CFG_APB1DIV_Pos 8
#define CRM_CFG_APB1DIV_Msk (0x7U << CRM_CFG_APB1DIV_Pos)
#define CRM_CFG_APB1DIV_1 (0x0U << CRM_CFG_APB1DIV_Pos)
/* APB2 Clock Divider */
#define CRM_CFG_APB2DIV_Pos 11
#define CRM_CFG_APB2DIV_Msk (0x7U << CRM_CFG_APB2DIV_Pos)
#define CRM_CFG_APB2DIV_1 (0x0U << CRM_CFG_APB2DIV_Pos)
/* PLL Reference Clock Source */
#define CRM_CFG_PLLRCS_Pos 16
#define CRM_CFG_PLLRCS_Msk (0x1U << CRM_CFG_PLLRCS_Pos)
#define CRM_CFG_PLLRCS_HICK (0x0U << CRM_CFG_PLLRCS_Pos)
#define CRM_CFG_PLLRCS_HEXT (0x1U << CRM_CFG_PLLRCS_Pos)
/* HEXT Clock Divider for PLL */
#define CRM_CFG_PLLHEXTDIV_Pos 17
#define CRM_CFG_PLLHEXTDIV_Msk (0x1U << CRM_CFG_PLLHEXTDIV_Pos)
#define CRM_CFG_PLLHEXTDIV_1 (0x0U << CRM_CFG_PLLHEXTDIV_Pos)
#define CRM_CFG_PLLHEXTDIV_2 (0x1U << CRM_CFG_PLLHEXTDIV_Pos)
/* PLL Multiplication Factor (split across two bit fields) */
#define CRM_CFG_PLLMULT_L_Pos 18 /* Low bits [21:18] - 4 bits */
#define CRM_CFG_PLLMULT_L_Msk (0xFU << CRM_CFG_PLLMULT_L_Pos)
#define CRM_CFG_PLLMULT_H_Pos 29 /* High bits [30:29] - 2 bits */
#define CRM_CFG_PLLMULT_H_Msk (0x3U << CRM_CFG_PLLMULT_H_Pos)
/*******************************************************************************
* CRM CTRL Register Bit Definitions
******************************************************************************/
/* HEXT Control */
#define CRM_CTRL_HEXTEN_Pos 16
#define CRM_CTRL_HEXTEN (0x1U << CRM_CTRL_HEXTEN_Pos)
#define CRM_CTRL_HEXTSTBL_Pos 17
#define CRM_CTRL_HEXTSTBL (0x1U << CRM_CTRL_HEXTSTBL_Pos)
/* PLL Control */
#define CRM_CTRL_PLLEN_Pos 24
#define CRM_CTRL_PLLEN (0x1U << CRM_CTRL_PLLEN_Pos)
#define CRM_CTRL_PLLSTBL_Pos 25
#define CRM_CTRL_PLLSTBL (0x1U << CRM_CTRL_PLLSTBL_Pos)
/*******************************************************************************
* CRM MISC2 Register Bit Definitions
******************************************************************************/
/* Auto-step Mode Control */
#define CRM_MISC2_AUTO_STEP_EN_Pos 4
#define CRM_MISC2_AUTO_STEP_EN_Msk (0x3U << CRM_MISC2_AUTO_STEP_EN_Pos)
#define CRM_MISC2_AUTO_STEP_EN (0x3U << CRM_MISC2_AUTO_STEP_EN_Pos)
/*******************************************************************************
* CRM Peripheral Clock Enable Register Bit Definitions
******************************************************************************/
/* AHB Peripheral Clock Enable */
#define CRM_AHBEN_GPIOAEN_Pos 17
#define CRM_AHBEN_GPIOAEN (0x1U << CRM_AHBEN_GPIOAEN_Pos)
/* APB1 Peripheral Clock Enable */
#define CRM_APB1EN_TMR14EN_Pos 8
#define CRM_APB1EN_TMR14EN (0x1U << CRM_APB1EN_TMR14EN_Pos)
/* APB2 Peripheral Clock Enable */
#define CRM_APB2EN_USART1EN_Pos 14
#define CRM_APB2EN_USART1EN (0x1U << CRM_APB2EN_USART1EN_Pos)
/*******************************************************************************
* Flash PSR Register Bit Definitions
******************************************************************************/
/* Flash Wait Cycles */
#define FLASH_PSR_WTCYC_Pos 0
#define FLASH_PSR_WTCYC_Msk (0x7U << FLASH_PSR_WTCYC_Pos)
#define FLASH_PSR_WTCYC_3 (0x3U << FLASH_PSR_WTCYC_Pos)
/* Flash Prefetch Control */
#define FLASH_PSR_PFT_EN_Pos 4
#define FLASH_PSR_PFT_EN (0x1U << FLASH_PSR_PFT_EN_Pos) /* Main prefetch enable */
#define FLASH_PSR_PFT_EN2_Pos 6
#define FLASH_PSR_PFT_EN2 (0x1U << FLASH_PSR_PFT_EN2_Pos) /* Prefetch buffer block 2 enable */
/*******************************************************************************
* PLL Configuration Based on Clock Source
******************************************************************************/
#ifdef HEXT_FREQUENCY
/* HEXT PLL configurations for different crystal frequencies targeting ~120MHz */
#if HEXT_FREQUENCY == 4
/* 4MHz HEXT -> 120MHz: 4MHz × 30 = 120MHz */
#define PLL_MULT_FACTOR 30
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_1
#elif HEXT_FREQUENCY == 8
/* 8MHz HEXT -> 120MHz: 8MHz × 15 = 120MHz */
#define PLL_MULT_FACTOR 15
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_1
#elif HEXT_FREQUENCY == 12
/* 12MHz HEXT -> 120MHz: 12MHz × 10 = 120MHz */
#define PLL_MULT_FACTOR 10
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_1
#elif HEXT_FREQUENCY == 16
/* 16MHz HEXT/2 -> 120MHz: 8MHz × 15 = 120MHz */
#define PLL_MULT_FACTOR 15
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_2
#elif HEXT_FREQUENCY == 20
/* 20MHz HEXT/2 -> 120MHz: 10MHz × 12 = 120MHz */
#define PLL_MULT_FACTOR 12
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_2
#elif HEXT_FREQUENCY == 25
/* 25MHz HEXT/2 -> 125MHz: 12.5MHz × 10 = 125MHz */
#define PLL_MULT_FACTOR 10
#define CRM_CFG_PLLRCS_SEL CRM_CFG_PLLRCS_HEXT
#define CRM_CFG_PLLHEXTDIV_SEL CRM_CFG_PLLHEXTDIV_2
#warning "25MHz crystal results in 125MHz system clock (not exactly 120MHz)"
#else
#error "Unsupported HEXT frequency. Supported: 4, 8, 12, 16, 20, 25 MHz"
#endif
/* Calculate PLL multiplication factor encoding for HEXT */
#define CRM_CFG_PLLMULT_L (((PLL_MULT_FACTOR - 2) & 0x0F) << CRM_CFG_PLLMULT_L_Pos)
#define CRM_CFG_PLLMULT_H (((PLL_MULT_FACTOR - 2) >> 4) << CRM_CFG_PLLMULT_H_Pos)
#else
/* HICK PLL configuration: 4MHz × 30 = 120MHz */
#define PLL_MULT_FACTOR 30
#define CRM_CFG_PLLMULT_L (0xEU << CRM_CFG_PLLMULT_L_Pos) /* Low 4 bits: 1110 */
#define CRM_CFG_PLLMULT_H (0x1U << CRM_CFG_PLLMULT_H_Pos) /* High 2 bits: 01 */
/* Note: PLLRCS = 0 (HICK) and PLLHEXTDIV = 0 by default, no need to OR with 0 */
#endif
/**
* @brief Configure CRM system clock and enable all used peripheral clocks
*
* System Clock Configuration:
* - System clock target = SYSTEM_CLOCK_HZ (120MHz or 125MHz for 25MHz crystal)
* - System clock source = PLL
* - AHB divider = 1 (HCLK = SCLK)
* - APB2 divider = 1 (PCLK2 = SCLK)
* - APB1 divider = 1 (PCLK1 = SCLK)
* - Auto-step mode = enabled (recommended for >108MHz)
* - Flash wait cycles = 3
* - Flash prefetch = enabled (both buffers)
*
* Enabled Peripheral Clocks:
* - GPIOA (for PA4, PA9, PA10)
* - TMR14 (for PWM output)
* - USART1 (for serial communication)
*/
void crm_config(void);
#endif /* CRM_H */
Код: Выделить всё
/**
* AT32F421 CRM (Clock and Reset Management) Implementation
*/
#include "crm.h"
/**
* @brief Configure CRM system clock and enable all used peripheral clocks
*/
void crm_config(void) {
uint32_t timeout;
#ifdef HEXT_FREQUENCY
/* Step 0: Enable and wait for HEXT (external crystal) to stabilize */
CRM->ctrl |= CRM_CTRL_HEXTEN;
timeout = CRM_HEXT_TIMEOUT;
while (!(CRM->ctrl & CRM_CTRL_HEXTSTBL)) {
if (--timeout == 0) {
/* HEXT failed to stabilize - handle error */
return;
}
}
#endif
/* Step 1: Configure PLL multiplication factor and source in CFG register */
CRM->cfg = CRM_CFG_PLLMULT_L | /* PLL multiplication factor - low bits */
#ifdef HEXT_FREQUENCY
CRM_CFG_PLLRCS_SEL | /* PLL source selection (HEXT) */
CRM_CFG_PLLHEXTDIV_SEL | /* HEXT divider */
#endif
CRM_CFG_PLLMULT_H; /* PLL multiplication factor - high bits */
/* Step 2: Enable PLL */
CRM->ctrl |= CRM_CTRL_PLLEN;
/* Step 3: Wait for PLL to become ready */
timeout = CRM_PLL_TIMEOUT;
while (!(CRM->ctrl & CRM_CTRL_PLLSTBL)) {
if (--timeout == 0) {
/* PLL failed to lock - handle error */
return;
}
}
/* Step 4: Enable auto-step mode for smooth clock switching (>108MHz) */
CRM->misc2 |= CRM_MISC2_AUTO_STEP_EN;
/* Step 5: Configure Flash for high-frequency operation with prefetch enabled */
FLASH->psr = FLASH_PSR_WTCYC_3 | /* 3 wait cycles for high frequency */
FLASH_PSR_PFT_EN | /* Enable main prefetch buffer */
FLASH_PSR_PFT_EN2; /* Enable prefetch buffer block 2 */
/* Step 6: Switch system clock to PLL */
CRM->cfg |= CRM_CFG_SCLKSEL_PLL;
/* Step 7: Wait for system clock switch to complete */
timeout = CRM_SWITCH_TIMEOUT;
while ((CRM->cfg & CRM_CFG_SCLKSTS_Msk) != CRM_CFG_SCLKSTS_PLL) {
if (--timeout == 0) {
/* Clock switch failed - handle error */
return;
}
}
/* Step 8: Disable auto-step mode after successful switch */
CRM->misc2 &= ~CRM_MISC2_AUTO_STEP_EN_Msk;
/* Step 9: Enable all peripheral clocks used in this project */
CRM->ahben |= CRM_AHBEN_GPIOAEN; /* Enable GPIOA clock */
CRM->apb1en |= CRM_APB1EN_TMR14EN; /* Enable TMR14 clock */
CRM->apb2en |= CRM_APB2EN_USART1EN; /* Enable USART1 clock */
}
Код: Выделить всё
/* APB2 clock enable register */
union
{
__IOM uint32_t APB2CLKEN;
struct
{
__IOM uint32_t AFIOEN : 1;
__IM uint32_t RESERVED1 : 1;
__IOM uint32_t PAEN : 1;
__IOM uint32_t PBEN : 1;
__IOM uint32_t PCEN : 1;
__IOM uint32_t PDEN : 1;
__IOM uint32_t PEEN : 1;
__IOM uint32_t PFEN : 1;
__IOM uint32_t PGEN : 1;
__IOM uint32_t ADC1EN : 1;
__IOM uint32_t ADC2EN : 1;
__IOM uint32_t TMR1EN : 1;
__IOM uint32_t SPI1EN : 1;
__IOM uint32_t TMR8EN : 1;
__IOM uint32_t USART1EN : 1;
__IOM uint32_t ADC3EN : 1;
__IM uint32_t RESERVED2 : 16;
} APB2CLKEN_B;
};У, какая замечательная китайщина! Т.е. они думают, что если побитно будут выставлять флажки в регистре, то gcc это все в одну инструкцию соберет! Видимо, что значит volatile, они не догадываются…RCM->APB2CLKEN_B.PAEN = BIT_SET;
Код: Выделить всё
RCM->APB2CLKEN_B = PAEN | PBEN | ...; Код: Выделить всё
RCM->APB2CLKEN_B = PAEN | PBEN | ...;