Lab4: bootloader

写一个自己的简易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);
						}
						else
							SerialPuts("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);
						}
						else
							SerialPuts("Format Error\r\n");
         }else{
					 SerialPuts("Instruction Error\r\n");
          }
        }
    }

测试结果:






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值