Lab4: bootloader

来源:互联网 发布:陈田村拆车件淘宝店 编辑:程序博客网 时间:2024/04/30 10:55

写一个自己的简易bootloader,能通过串口执行两条最简单的指令:

l  peek addr 以一个字为单位读取内存中addr 位置的数据(addr是4字节对齐,十六进制的 形式,长度为8位十六进制,例如 0x00008000),并以十六进制的形式输出

l  poke addr data 以一个字为单位修改内存中 addr 位置的数据为 data(addr 是 4 字节对齐,十六进制的形式,长度为 8位十六进制, data 也是十六进制的形式,长度为8位十六进制)


实际连接图


定义全局变量:

#define BUFFSIZE 512#define BACKSPACE 127#define ENTER '\r'char str[100] = "Uart";struct uart {      uint8_t *rear;    uint8_t *front;};uint8_t aRxBuffer[BUFFSIZE];  struct uart uart_rev; 

aRxBuffer数组用来接收缓冲区数组,结构uart用来接收缓冲区头尾指针。

输出重定义:

void SerialPutchar(char s){    HAL_UART_Transmit(&huart1, (uint8_t*)&s, 1, 500);}void SerialPuts(char* s){int i=0;while(s[i] != '\0'){SerialPutchar(s[i]);i++;}}
void ptrInc(uint8_t **ptr, uint8_t* base, int len){    *ptr += 1;    if (*ptr >= base + len)        *ptr = base;}

3)串口收发

串口接受采用中断接收至环形缓冲区的处理方式。生成工程后,uart_init()函数执行串口初始化,并设置中断优先级。

void uart_init(uint32_t BaudRate)  {  huart1.Instance = USART1;    huart1.Init.BaudRate = 9600;    huart1.Init.WordLength = UART_WORDLENGTH_8B;    huart1.Init.StopBits = UART_STOPBITS_1;    huart1.Init.Parity = UART_PARITY_NONE;    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;    huart1.Init.Mode = UART_MODE_TX_RX;    HAL_UART_Init(&huart1);    __HAL_UART_ENABLE(&huart1);          NVIC_SetPriority(USART1_IRQn, 0);    NVIC_EnableIRQ(USART1_IRQn);      uart_rev.front = aRxBuffer;      uart_rev.rear = aRxBuffer;         if (HAL_UART_Receive_IT(&huart1, (uint8_t*)aRxBuffer, 1) != HAL_OK){         HAL_UART_Transmit(&huart1, (uint8_t*)"error_h", 7, 500);    }}

USART1_IRQHandler()调用HAL_UART_IRQHandler()函数,处理中断。

函数末尾调用HAL_UART_Receive_IT函数,设置串口数据的存储位置,该函数会设置存储位置和接受长度,当接收的数据达到指定长度时,会进入中断回调函数 HAL_UART_RxCpltCallback() 处理中断。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)  {      uint8_t ret = HAL_OK;    char c = *uart_rev.rear;    SerialPutchar(c);    if (c == '\r'){        SerialPutchar('\n');    }    ptrInc(&uart_rev.rear, aRxBuffer, BUFFSIZE);    if (uart_rev.rear == uart_rev.front)        ptrInc(&uart_rev.front, aRxBuffer, BUFFSIZE);    do{          ret = HAL_UART_Receive_IT(UartHandle, uart_rev.rear, 1);      }while(ret != HAL_OK);}void uart_init(uint32_t BaudRate)  {  huart1.Instance = USART1;    huart1.Init.BaudRate = 9600;    huart1.Init.WordLength = UART_WORDLENGTH_8B;    huart1.Init.StopBits = UART_STOPBITS_1;    huart1.Init.Parity = UART_PARITY_NONE;    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;    huart1.Init.Mode = UART_MODE_TX_RX;    HAL_UART_Init(&huart1);    __HAL_UART_ENABLE(&huart1);          NVIC_SetPriority(USART1_IRQn, 0);    NVIC_EnableIRQ(USART1_IRQn);      uart_rev.front = aRxBuffer;      uart_rev.rear = aRxBuffer;         if (HAL_UART_Receive_IT(&huart1, (uint8_t*)aRxBuffer, 1) != HAL_OK){         HAL_UART_Transmit(&huart1, (uint8_t*)"error_h", 7, 500);    }}

串口信息读取到环形缓存区存放

int8_t uart_read(uint8_t *fmt, uint16_t time_out){      while(time_out){          if(uart_rev.front != uart_rev.rear){              *fmt=*uart_rev.front;            ptrInc(&uart_rev.front, aRxBuffer, BUFFSIZE);            return 0;          }      time_out--;      }      return (int8_t)-1;  }int8_t uart_gets(uint8_t *fmt, uint16_t upperBound)  {      int count = 0;        upperBound -= 1;      while(count < upperBound){          if(uart_rev.front != uart_rev.rear){   char c = *uart_rev.front;            ptrInc(&uart_rev.front, aRxBuffer, BUFFSIZE);                        if (c == ENTER){                break;            }                      *fmt = c;                       if (c != BACKSPACE){                fmt++;                count++;            }else if(count > 0){                fmt--;                count--;            }        }    }    *fmt = '\0';    return count;  }

到这里,对于串口收发的函数封装完成,处理peek/poke指令。为了防止随便给poke指令的地址,崩坏程序,所以给了buff数组,并给出相应的地址及长度。

int buff[100];    buff[0] = sprintf(str, "Buffer Addr: %p Len: %d\r\n", buff, 100);    HAL_UART_Transmit(&huart1, (uint8_t*)str, buff[0], 500);    while (1) {        int count = 0;        char s[100];        char cmd[100];        SerialPuts("STM32 > ");                count = uart_gets((uint8_t*)str, 100);        sscanf(str, "%s", cmd);        if (strcmp(cmd, "peek") == 0){  int addr = 0, args = 0;            args = sscanf(str + 5, "%x %s", &addr, s);if(args == 1){sprintf(s, "PEEK: %x %x\r\n", addr, *((int*)addr));SerialPuts(s);}elseSerialPuts("Format Error\r\n");        }else if(strcmp(cmd, "poke") == 0){int addr = 0, args = 0, data=0;            args = sscanf(str + 5, "%x %x %s", &addr, &data, s);if(args == 2){*((int*)addr) = data;sprintf(s, "POKE: %x %x\r\n", addr, *((int*)addr));SerialPuts(s);}elseSerialPuts("Format Error\r\n");         }else{ SerialPuts("Instruction Error\r\n");          }        }    }

测试结果:






0 0