Files
templates/c/rs485-boot/ports/stm32g474vet/rs485_boot_stm32g474vet.c

24 lines
3.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Порт RS-485-загрузчика для STM32G474VET с аппаратными операциями Flash. Конфигурация задаёт
* область приложения, а обработчик проверяет BUSY и ошибки программирования до подтверждения
* операции.
*/
#include "rs485_boot_stm32g474vet.h"
#include "rs485_boot_port_config.h"
#include "stm32g474xx.h"
#include <string.h>
static bool fw(void){while(FLASH->SR&FLASH_SR_BSY){}if(FLASH->SR&(FLASH_SR_OPERR|FLASH_SR_PROGERR|FLASH_SR_WRPERR|FLASH_SR_PGAERR|FLASH_SR_SIZERR|FLASH_SR_PGSERR)){FLASH->SR=FLASH_SR_OPERR|FLASH_SR_PROGERR|FLASH_SR_WRPERR|FLASH_SR_PGAERR|FLASH_SR_SIZERR|FLASH_SR_PGSERR;return false;}return true;}
static void ul(void){if(FLASH->CR&FLASH_CR_LOCK){FLASH->KEYR=0x45670123UL;FLASH->KEYR=0xCDEF89ABUL;}}
static void lk(void){FLASH->CR|=FLASH_CR_LOCK;}
void rs485_boot_hw_init(void){RCC->AHB2ENR|=RCC_AHB2ENR_GPIOAEN;RCC->APB2ENR|=RCC_APB2ENR_USART1EN;GPIOA->MODER=(GPIOA->MODER&~((3UL<<16)|(3UL<<18)|(3UL<<20)))|(1UL<<16)|(2UL<<18)|(2UL<<20);GPIOA->AFR[1]=(GPIOA->AFR[1]&~((0xFUL<<4)|(0xFUL<<8)))|(7UL<<4)|(7UL<<8);GPIOA->BSRR=1UL<<(RS485_BOOT_DE_PIN+16U);USART1->BRR=(RS485_BOOT_UART_CLOCK_HZ+RS485_BOOT_BAUDRATE/2U)/RS485_BOOT_BAUDRATE;USART1->CR1=USART_CR1_TE|USART_CR1_RE|USART_CR1_UE;}
bool rs485_boot_hw_get_byte(uint8_t*b){uint32_t s=USART1->ISR;if(s&(USART_ISR_ORE|USART_ISR_FE|USART_ISR_NE)){USART1->ICR=USART_ICR_ORECF|USART_ICR_FECF|USART_ICR_NECF;return false;}if(!(s&USART_ISR_RXNE_RXFNE))return false;*b=(uint8_t)USART1->RDR;return true;}
static bool tx(void*u,const uint8_t*d,uint16_t n){uint16_t i;(void)u;GPIOA->BSRR=1UL<<RS485_BOOT_DE_PIN;for(i=0;i<n;i++){while(!(USART1->ISR&USART_ISR_TXE_TXFNF)){}USART1->TDR=d[i];}while(!(USART1->ISR&USART_ISR_TC)){}USART1->ICR=USART_ICR_TCCF;GPIOA->BSRR=1UL<<(RS485_BOOT_DE_PIN+16U);return true;}
static bool er(void*u,uint32_t n){uint32_t a,e;(void)u;if(!n||n>RS485_BOOT_FLASH_END-RS485_BOOT_APP_ADDRESS)return false;e=RS485_BOOT_APP_ADDRESS+((n+RS485_BOOT_FLASH_PAGE-1U)&~(RS485_BOOT_FLASH_PAGE-1U));ul();for(a=RS485_BOOT_APP_ADDRESS;a<e;a+=RS485_BOOT_FLASH_PAGE){uint32_t pg=(a-0x08000000UL)/RS485_BOOT_FLASH_PAGE;FLASH->CR=(FLASH->CR&~(FLASH_CR_PNB_Msk|FLASH_CR_BKER))|FLASH_CR_PER|(pg<<FLASH_CR_PNB_Pos);FLASH->CR|=FLASH_CR_STRT;if(!fw()){lk();return false;}FLASH->CR&=~FLASH_CR_PER;}lk();return true;}
static bool wr(void*u,uint32_t o,const uint8_t*d,uint16_t n){uint16_t z=0;(void)u;if((o&7U)||o+n>RS485_BOOT_FLASH_END-RS485_BOOT_APP_ADDRESS)return false;ul();while(z<n){uint64_t v=UINT64_MAX;uint16_t take=(uint16_t)(n-z);if(take>8)take=8;memcpy(&v,&d[z],take);FLASH->CR|=FLASH_CR_PG;*(volatile uint32_t*)(RS485_BOOT_APP_ADDRESS+o+z)=(uint32_t)v;*(volatile uint32_t*)(RS485_BOOT_APP_ADDRESS+o+z+4)=(uint32_t)(v>>32);if(!fw()){FLASH->CR&=~FLASH_CR_PG;lk();return false;}FLASH->CR&=~FLASH_CR_PG;z=(uint16_t)(z+take);}lk();return true;}
static bool rd(void*u,uint32_t o,uint8_t*d,uint16_t n){(void)u;if(o+n>RS485_BOOT_FLASH_END-RS485_BOOT_APP_ADDRESS)return false;memcpy(d,(const void*)(RS485_BOOT_APP_ADDRESS+o),n);return true;}
static bool ok(void*u,uint32_t n,uint32_t c){uint32_t sp=*(const uint32_t*)RS485_BOOT_APP_ADDRESS,rv=*(const uint32_t*)(RS485_BOOT_APP_ADDRESS+4);(void)u;return sp>=0x20000000UL&&sp<0x20020000UL&&(rv&1U)&&(rv&~1UL)>=RS485_BOOT_APP_ADDRESS&&(rv&~1UL)<RS485_BOOT_FLASH_END&&rs485_boot_crc32((const uint8_t*)RS485_BOOT_APP_ADDRESS,n)==c;}
static void reset(void*u){(void)u;NVIC_SystemReset();}
rs485_boot_config_t rs485_boot_hw_config(void){rs485_boot_config_t c={RS485_BOOT_APP_ADDRESS,RS485_BOOT_FLASH_END-RS485_BOOT_APP_ADDRESS,RS485_BOOT_MAX_BLOCK};return c;}
rs485_boot_port_t rs485_boot_hw_make_port(void){rs485_boot_port_t p={tx,er,wr,rd,ok,reset};return p;}