HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6

в 10:19, , рубрики: HK32F030, stm32f030, программирование микроконтроллеров, Производство и разработка электроники

Сперва лёгкая прелюдия...

STMicroelectronics за последние 4-5 месяцев заставила мелких и средне сочных производителей микроэлектроники капитально "затянуть пояса". Не секрет что за это время оригинальные чипы капитально взлетели в цене, а последние пару месяцев чипов так вообще и не достать... Поэтому потянулись, в связи с дефицитом, к китайским аналогам.

Вот к примеру HK32F030C8T6 по заявлениям производителя (Шэньчжэнь Hangshun Chip Technology R&D Co., Ltd.) является полной копией своего с позволения сказать старшего брата STM32F030C8T6. Итак, давайте посмотрим...

Открываем техническую документацию...

Судя по описанию: "HK32F030x4 / HK32F030x6 / HK32F030x8. HK32F030 Перечисленные микросхемы разработаны компанией Shenzhen Haohan Tianji Processor Co., Ltd., дочерней компанией Shenzhen Hangshun Chip Technology Research Co., Ltd.".

И тут честно говоря я был в восторге! Во первых чипы могут работать в диапазоне питающего напряжения от 2,0 В до 5,5 В. Во вторых: максимальная тактовая частота ядра аж до 72 МГц!!! Прям сказка да и только!!! Убедитесь сами!!!:

Скрин тех. документа
HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 1

Ах да. "Даташит" на китайском...

...читаем дальше!!!

Скрин тех. документа
HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 2

Тут я добираюсь до функциональной схемы модуля генерации частот... и слегка недоумеваю...

HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 3

...что такое RCC_CFGR4, у STM'ки его нет! Открываем библиотечный файл "stm32f0xx.h":

typedef struct
{
  __IO uint32_t CR;         /*!< RCC clock control register,                                  Address offset: 0x00 */
  __IO uint32_t CFGR;       /*!< RCC clock configuration register,                            Address offset: 0x04 */
  __IO uint32_t CIR;        /*!< RCC clock interrupt register,                                Address offset: 0x08 */
  __IO uint32_t APB2RSTR;   /*!< RCC APB2 peripheral reset register,                          Address offset: 0x0C */
  __IO uint32_t APB1RSTR;   /*!< RCC APB1 peripheral reset register,                          Address offset: 0x10 */
  __IO uint32_t AHBENR;     /*!< RCC AHB peripheral clock register,                           Address offset: 0x14 */
  __IO uint32_t APB2ENR;    /*!< RCC APB2 peripheral clock enable register,                   Address offset: 0x18 */
  __IO uint32_t APB1ENR;    /*!< RCC APB1 peripheral clock enable register,                   Address offset: 0x1C */
  __IO uint32_t BDCR;       /*!< RCC Backup domain control register,                          Address offset: 0x20 */ 
  __IO uint32_t CSR;        /*!< RCC clock control & status register,                         Address offset: 0x24 */
  __IO uint32_t AHBRSTR;    /*!< RCC AHB peripheral reset register,                           Address offset: 0x28 */
  __IO uint32_t CFGR2;      /*!< RCC clock configuration register 2,                          Address offset: 0x2C */
  __IO uint32_t CFGR3;      /*!< RCC clock configuration register 3,                          Address offset: 0x30 */
  __IO uint32_t CR2;        /*!< RCC clock control register 2,                                Address offset: 0x34 */
} RCC_TypeDef;

Но сравнив данный модуль с оригинальным, я понимаю что на CFGR4 мне пофиг, куска которым управляет данный регистр у оригинального чипа нет:

HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 4

...просмотрев весь документ я понимаю что информации о чипе в документе явно не достаточно, можно было бы предположить что в нем точно повторен STM32F030, однако тут я вспомнил про регистр CFGR4...

В итоге прорыв просторы интернета я таки нашел ссылку на неведомую библиотеку HK32F0_LibraryV1.0.3... и оказывается вон оно как:

typedef struct
{
  __IO uint32_t CR;            /*!< RCC clock control register,                                   Address offset: 0x00 */
  __IO uint32_t CFGR;       /*!< RCC clock configuration register,                            Address offset: 0x04 */
  __IO uint32_t CIR;        /*!< RCC clock interrupt register,                                Address offset: 0x08 */
  __IO uint32_t APB2RSTR;   /*!< RCC APB2 peripheral reset register,                          Address offset: 0x0C */
  __IO uint32_t APB1RSTR;   /*!< RCC APB1 peripheral reset register,                          Address offset: 0x10 */
  __IO uint32_t AHBENR;     /*!< RCC AHB peripheral clock register,                           Address offset: 0x14 */
  __IO uint32_t APB2ENR;    /*!< RCC APB2 peripheral clock enable register,                   Address offset: 0x18 */
  __IO uint32_t APB1ENR;    /*!< RCC APB1 peripheral clock enable register,                   Address offset: 0x1C */
  __IO uint32_t BDCR;       /*!< RCC Backup domain control register,                          Address offset: 0x20 */
  __IO uint32_t CSR;        /*!< RCC clock control & status register,                         Address offset: 0x24 */
  __IO uint32_t AHBRSTR;    /*!< RCC AHB peripheral reset register,                           Address offset: 0x28 */
  __IO uint32_t CFGR2;      /*!< RCC clock configuration register 2,                          Address offset: 0x2C */
  __IO uint32_t CFGR3;      /*!< RCC clock configuration register 3,                          Address offset: 0x30 */
  __IO uint32_t CR2;        /*!< RCC clock control register 2,                                Address offset: 0x34 */
   uint32_t RESERVED[42];      /*!< Reserved,                                                    Address offset: 0x38-dc */
  __IO uint32_t HSECTL;      /*!< RCC clock HSE control,                                      Address offset: 0xe0 */
    uint32_t RESERVED1;      /*!< Reserved,                                                    Address offset: 0xe4 */
  __IO uint32_t CFGR4;        /*!< RCC clock control register 4,                              Address offset: 0xe8 */ 
  __IO uint32_t AHBENR2;      /*!< RCC clock configuration ahb,                               Address offset: 0xec */
} RCC_TypeDef;

...интересно китайцы специально отступили (uint32_t RESERVED[42]; /*!< Reserved) чтоб в лоб не получилось найти доп регистры или это фишка реализации?

Посмотрев библиотеку, увидел что по регистрам периферии прям одно и то же с оригиналом! Ну дык и давайте шить прошивку!!! (...достаю из закромов родины забавную программную реализацию USB для STM32F0xx...) Зашиваю, и получаю:

HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 5

Не понял, беру STM32F030, зашиваю:

HK32F030C8T6 全功能克隆 (полный функциональный клон) STM32F030C8T6 - 6

Но я ж не просто так, меня попросили помочь переехать с STM на HK и чтоб программное USB работало... и тут мне слегка не по себе стало... кто реализовывал программный USB на ARM, тому наверное сразу вспомниться цитата из документашки: "NOP performs no operation and is not guaranteed to be time consuming. The processor might remove it from the pipeline before it reaches the execution stage. " Иными словами NOP пользуется для выравнивания команд и с конвейера его проц может "выплевывать" не задерживаясь на выполнение пустой операции... но я не совсем про это говорю, как ровнять тайминги если неизвестно сколько тактов тратит каждая инструкция?

Этож целая экспедиция переписать тактозависимые функции приема и передачи для ядра ARM!!!

Тут абсолютно понятно что HK явно не является "клоном" по количеству тактов на инструкции. Однако где найти документацию по ассемблерным командам и самое главное по тактам затрачиваемым на выполнение.

...

И тут нам поможет System Tick Timer! Настраиваем его, отключаем прерывания, не включаем Watchdog (чтоб проц не отвлекался на что-то иное кроме выполнения). Переходим в отладчик, выполняем инструкции по шагам и сравниваем сколько успел насчитать таймер во время выполнения инструкции. Берем два абсолютно одинаковых куска кода и сравниваем кол-во тактов на инструкцию:

Оригинал (STM32F030):

asm_usb_tx
        PUSH     {R4-R7,LR}			;10
        LDR      R3,DataTable+0x08 	;6
        LDR      R2,DataTable+0x14 	;6
        STR      R2,[R3, #+0x18]	;5
        LDR      R4,[R3, #+0]		;5
        MOVS     R5,#+5				;4
        LSLS     R5,R5,#+22			;4
        ORRS     R5,R5,R4			;4
        STR      R5,[R3, #+0]		;5
        MOVS     R7,#+0				;4
        ADDS     R1,R1,#+1			;4
ut_0
        LDRB     R5,[R0,#+0]		;5
        NOP							;4
        NOP							;4
        SUBS     R1,R1,#+1			;4
        BEQ      ut_2				;4
        MOVS     R6,#+8				;4
        LDRB     R4,[R0,#+0]		;5
        ADDS     R0,R0,#+1			;4

"Китайское" (HK32F030):

asm_usb_tx
        PUSH     {R4-R7,LR}			;10
        LDR      R3,DataTable+0x08	;6
        LDR      R2,DataTable+0x14	;6
        STR      R2,[R3, #+0x18] 	;9 GPIOA->BSRR
        LDR      R4,[R3, #+0]		;8 GPIOA->MODER
        MOVS     R5,#+5				;4
        LSLS     R5,R5,#+22			;4
        ORRS     R5,R5,R4			;4
        STR      R5,[R3, #+0]		;6 GPIOA->MODER
        MOVS     R7,#+0				;4
        ADDS     R1,R1,#+1			;4
ut_0
        LDRB     R5,[R0,#+0]		;9
        NOP							;4
        NOP							;4
        SUBS     R1,R1,#+1			;4
        BEQ      ut_2				;4->8
        MOVS     R6,#+8				;4
        LDRB     R4,[R0,#+0]		;9 Load transmited Byte
        ADDS     R0,R0,#+1			;6 Increment TX Buffer Pointer

Вот блин бабушка и приехали... Инструкции LDR/STR выполняются в полтора раза дольше и те же инструкции тратят на один такт больше если используем Immediate Value... и мало того, - по сути идентичные инструкции выполняются разное кол-во тактов, и ещё опа, - времени банально не хватает на текущую реализацию... Пусть, ядро может работать на 72 MHz, пробуем.

Меняем множитель с 6 на 9. И в теории, времени теперь навалом, а по факту впритык, потому что проц пожирает массу времени на часто используемые команды, подгоняем реализацию под нужные временные интервалы антинаучным методом "подбора" и "научного тыка". И теперь оно работает.

Резюме:

...HK это не STM...

  1. Отсутствие нормальной документации, если разработчики подумали что фиг с ним, есть стандартный мануал от STM, там читайте, то хоть бы скопипастили даташит, не понятно даже где адреса GPIO. Текущий документ выглядит так как будто начали писать, потом устали.

  2. Микроконтроллер HK по периферии, похож на STM, лично я проверил ADC/TIM/USART/IWDG/GPIO, - работают схоже, но документации точной нет, поэтому угадайка где что вылезет.

  3. Не предсказуемое время выполнения кода и даже заявленное преимущество в 72MHz собственно полностью "закрашивается" временем выполнения операций условного перехода и загрузкой/выгрузкой регистров. "Слегка" промахнулись с "фетчем" инструкций и данных. При переезде на этот проц, если вы работали на STM'ке на 48MHz, задирайте на HK частоту до 72, так как среднее время выполнения "по поликлинике" на 48MHz для STM приблизительно будет равно для HK на 72MHz, и придется переписывать все таймеры ибо 72 != 48, а таймеры, неожиданно прям, тикают в этих кристаллах одинаково.

За сим разрешите откланяться.

Отличного дня! Благ, доброты и удачи.

Автор: Михаил Шероносов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js