117.龙芯2k1000-pmon(16)- linux下升级pmon

pmon的升级总是有些不方便,至少是要借助串口和串口工具

如果现场不方便连接串口,是不是可以使用网线升级pmon呢?

答案当然是可行的。

环境:2k1000+linux3.10+麒麟的文件系统

如今我已经把这个工具开发出来了。

GitHub - zhaozhi0810/pmon-ls2k1000-2022  tools/program-2k1000-pmon 目录下包含源码,还有编译出来的工具。

烧录的过程大概需要1分钟左右。可以稍微等待一下!!

我这做了一些选项   (修改dtb的部分没有实现,暂时好像没有这个需求)

    选项
    -o gzrom-dtb-new.bin 读出flash中的程序(1m以内)
    -e env.bin 写入env数据:要求有校验和+正确的格式
    -d dtb.bin  写入dtb
    -c gzrom-dtb.bin  比较flash中的与文件是否相同(只比较0-0xfb000这一段)

    -w gzrom-dtb.bin 直接写入gzrom-dtb.bin
    gzrom-dtb.bin 与-w的功能相同 

我升级了很多次,确定没有问题才分享出来。(但是仍然有风险,风险自担)

下面是源码:(两个c文件一起编译就可以了)

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>/*2024-03-02  by dazhi特别注意: ls2k1000 的pmon 不能大于1m ,因为它映射的空间就是1m以内env的起始位置0x1fcff000,大小498字节以内,还有2个字节的校验和,最大不能超过500字节dtb的起始位置0x1fcfb000,大小16k-8字节,8个字节留出来做校验和,最大不能超过16kgzrom的起始位置0x1fc00000,最大1004k字节。选项-o gzrom-dtb-new.bin 读出flash中的程序(1m以内)-e env.bin 写入env数据:要求有校验和+正确的格式-d dtb.bin  写入dtb-c gzrom-dtb.bin  比较flash中的与文件是否相同gzrom-dtb.bin 直接写入gzrom-dtb.bin */#define BIN_FILE_SIZE 1044980   //这是编译的gzrom-dtb.bin的大小//extern int spiflash_main(char *cmd, unsigned long flashbase, unsigned long spiregbase, unsigned long spimem_base_map, ...);
//off 就是flash内部的偏移地址
//extern int fl_erase_device(int off, int size, int verbose);//off 就是flash内部的偏移地址
//extern int fl_program_device(int off, void *data_base, int data_size, int verbose);extern int set_spiflash_regaddr(unsigned long long spireg_base,void* spimem_base);
extern void tgt_flashprogram(int p, int size, void *s);
// off 是flash中的偏移地址,起始地址0
// data_base 是文件内容的缓存起始地址
// data_size 是需要比较的数据大小
// verbose 是否打印信息
extern int fl_verify_device(int off, void *data_base, int data_size, int verbose);int PAGE_SIZE;
int PAGE_MASK;#define FLASH_SIZE 0x500000void printf_usage(char* name)
{printf("USAGE:\n");printf("%s [-o gzrom-dtb-new.bin] : read flash(1M) to  file gzrom-dtb-new.bin\n",name);printf("%s <-e env.bin> : write env.bin to flash offset 0xff000,size 500Bytes\n",name);printf("%s <-d dtb.bin> : write dtb.bin to flash offset 0xfb000,size 16KBytes\n",name);printf("%s <-c gzrom-dtb.bin> : compare flash(ahout 600K) and file gzrom-dtb.bin,the same or not\n",name);printf("%s <-w gzrom-dtb.bin> : write gzrom-dtb.bin to flash offset 0,size 1044980Bytes\n",name);printf("%s <gzrom-dtb.bin> : the same with -w\n",name);printf("others ,not support!!!!\n");
}unsigned int flash_buf[FLASH_SIZE];
int main(int argc, char **argv)
{int fd,mem_fd,spimem_physaddr,spimem_map_len,spireg_physaddr,spireg_map_len,spireg_offset;void *spimem_base = NULL,*spireg_base= NULL,*buf=NULL;int i;int err;unsigned char* pbuf;int option = 0;   //0表示读出来char* filename = "gzrom-dtb-new.bin";   //文件名struct stat statbuf;if(argc > 3) //参数多余3个{printf_usage(argv[0]);return -1;}else if(argc == 2){printf("len = %d\n",strlen(argv[1]));if(strlen(argv[1]) > 8){printf("name = %s ,%s\n",argv[1],argv[1]+(strlen(argv[1])-4));if(strcmp(".bin",argv[1]+(strlen(argv[1])-4)) != 0)  //是.bin 结尾的吗{printf_usage(argv[0]);return -1;}}else{printf_usage(argv[0]);return -1;}option = 4;  //write gzrom-dtb ro flashfilename = argv[1];  //保存文件名;}else if(argc == 1){option = 0;}else  //argc == 3{filename = argv[2];  //保存文件名;if(strcmp(argv[1], "-o")==0){option = 0;}else if(strcmp(argv[1], "-e")==0){option = 1;  //写环境变量 env}else if(strcmp(argv[1], "-d")==0){option = 2;  //写dtb文件 }else if(strcmp(argv[1], "-c")==0){option = 3;  //比较文件}else if(strcmp(argv[1], "-w")==0){option = 4;  //write gzrom-dtb ro flash	}else{  //其他不能识别printf_usage(argv[0]);return -1;} }printf("opt = %d filename = %s\n",option,filename);spimem_physaddr = 0x1fc00000;   //0x1d000000; //3a5000的地址   //0x1fc00000 2k1000的地址spimem_map_len = 0x100000;//1MPAGE_SIZE = getpagesize();PAGE_MASK = (~(PAGE_SIZE-1));mem_fd = open("/dev/mem", O_RDWR|O_SYNC);if(mem_fd == -1)error(-1,errno,"error open /dev/mem\n");//spi 内存读写方式spimem_base = mmap(0, spimem_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spimem_physaddr&PAGE_MASK);if(spimem_base == MAP_FAILED)error(err,errno,"spimem_base map failed.\n");spireg_physaddr = 0x1fff0220;//0x1fe001f0;    //0x1fff0220 2k1000的地址spireg_map_len = 0x1000; //4Kspireg_offset = spireg_physaddr & (PAGE_SIZE-1);   //偏移地址spireg_base = (unsigned char*)mmap(NULL, spireg_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spireg_physaddr&PAGE_MASK);if(spireg_base == MAP_FAILED){error(err,errno,"spireg_base map failed.\n");return -1;}close(mem_fd);pbuf = spimem_base;//printf("spireg_base = %p\n",spireg_base);// 需要设置一下才能用啊。。。。set_spiflash_regaddr((unsigned long long) spireg_base + spireg_offset,spimem_base);// for(i=0;i<100;i++)// {//     printf("%02hhx ",pbuf[i]);//     if(i%16 ==15)//         printf("\n");// }//是读操作if(option == 0)  //读出flash的内容,大小BIN_FILE_SIZE个字节{fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,0666);if(fd == -1)error(err,errno,"error open file.\n");int ret =	write(fd,pbuf,BIN_FILE_SIZE);  //一次性写进去printf("read size = %d\n",ret);close(fd);}else if(option == 1) //写环境变量 env{//1 打开env。bin文件,限制文件不能大于500字节fd = open(filename, O_RDONLY);if(fd == -1)error(err,errno,"error open file. %s\n",filename);int size = lseek(fd,0,SEEK_END);  //长度if(size > 500){printf("file size too large (len=%d > 500Bytes)\n",size);munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);  close(fd);return -1;}lseek(fd,0,SEEK_SET);  //buf = mmap(0, 500, PROT_READ, MAP_SHARED, fd, 0);if(buf == MAP_FAILED)error(err,errno,"map failed.%s\n",filename);// 第一个参数是 flash中的地址,从0开始// 第二个参数是 写入字节数// 第三个参数需要写入内容缓存的起始地址tgt_flashprogram(0xff000, size, buf);close(fd);//取消映射munmap(buf,500);printf("erase and program down\n");}else if(option == 4) //write gzrom-dtb ro flash{if(strncmp("gzrom",filename,5) != 0 ){printf_usage(argv[0]);munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);return -1;}//1 打开gzrom-dtb.bin文件,限制文件大小fd = open(filename, O_RDONLY);if(fd == -1)error(err,errno,"error open file. %s\n",filename);int size = lseek(fd,0,SEEK_END);  //长度if(size != BIN_FILE_SIZE){printf("file size !=  %d\n",size,BIN_FILE_SIZE);munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);  close(fd);return -1;}lseek(fd,0,SEEK_SET);  //buf = mmap(0, BIN_FILE_SIZE, PROT_READ, MAP_SHARED, fd, 0);if(buf == MAP_FAILED)error(err,errno,"map failed.%s\n",filename);// 第一个参数是 flash中的地址,从0开始// 第二个参数是 写入字节数// 第三个参数需要写入内容缓存的起始地址tgt_flashprogram(0, BIN_FILE_SIZE, buf);   //起始地址是0printf("program %s done\n",filename);close(fd);//取消映射munmap(buf,BIN_FILE_SIZE);//printf("erase and program down\n");}else if(option == 3)  //比较文件,只比较前面0~0xfb000,后面的dtb没有必要比较{if(strncmp("gzrom",filename,5) != 0 ){printf_usage(argv[0]);munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);return -1;}//1 打开gzrom-dtb.bin文件,限制文件大小fd = open(filename, O_RDONLY);if(fd == -1)error(err,errno,"error open file. %s\n",filename);int size = lseek(fd,0,SEEK_END);  //长度if(size != BIN_FILE_SIZE){printf("file size !=  %d\n",size,BIN_FILE_SIZE);munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);  close(fd);return -1;}lseek(fd,0,SEEK_SET);  //buf = mmap(0, BIN_FILE_SIZE, PROT_READ, MAP_SHARED, fd, 0);if(buf == MAP_FAILED)error(err,errno,"map failed.%s\n",filename);int ret = fl_verify_device(0, buf, 0xfb000, 1);printf("compare %s done\n",filename);if(ret == 1)printf("file in system is the same with the file %s\n",filename);else if(ret == 0)printf("you can update this %s now!!!\n",filename);close(fd);//取消映射munmap(buf,BIN_FILE_SIZE);}munmap(spireg_base,spireg_map_len);munmap(spimem_base,spimem_map_len);     return 0;
}

这个spi_w 来自pmon的源码,但是有小部分修改

/*
* @Author: dazhi
* @Date:   2024-03-05 15:29:25
* @Last Modified by:   dazhi
* @Last Modified time: 2024-03-06 14:33:40
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//#include <pmon.h>
//#include <include/types.h>
//#include <pflash.h>#define TRUE 1
#define FALSE 0//#define SPI_BASE  0x1fff0220
//#define PMON_ADDR 0xa1000000
//
unsigned long long SPI_BASE;   //reg 的基地址void* spi_mem_base_addr;   //lonsoon 映射的内存地址#define PAGE_SIZE_4K 0x1000    //4k
#define PAGE_MASK_4K (PAGE_SIZE_4K-1)#define FLASH_ADDR 0x000000#define SPCR      0x0
#define SPSR      0x1
#define TXFIFO    0x2
#define RXFIFO    0x2
#define SPER      0x3
#define PARAM     0x4
#define SOFTCS    0x5
#define PARAM2    0x6#define WFFULL (1<<3)   //发送缓存满
#define RFEMPTY 1
#define KSEG1_STORE8(addr,val)	 *(volatile char *)(addr) = val
#define KSEG1_LOAD8(addr)	 *(volatile char *)(addr) #define SET_SPI(addr,val)        KSEG1_STORE8(SPI_BASE+addr,val)
#define GET_SPI(addr)            KSEG1_LOAD8(SPI_BASE+addr)
#define NEW_SPI_ZZstatic int delay(int value)
{int i, j;for (i = 0; i < value; i++) {for (j = 0; j < 100; j++) {;}}return 0;
}int set_spiflash_regaddr(unsigned long long spireg_base,void* spimem_base)
{   //寄存器的偏移地址SPI_BASE = spireg_base;spi_mem_base_addr = spimem_base;//printf("spi_base = %llx\n",SPI_BASE);
}int write_sr(char val);
void spi_initw()
{ //printf("11spi_base = %llx\n",SPI_BASE);SET_SPI(SPSR, 0xc0);   SET_SPI(PARAM, 0x40);    //这里没有读使能了         //espr:0100SET_SPI(SPER, 0x05); //spre:01 SET_SPI(PARAM2,0x01); SET_SPI(SPCR, 0x50);//printf("11spi_base = %llx\n",SPI_BASE);
}void spi_initr()
{SET_SPI(PARAM, 0x47);             //espr:0100
}#ifdef NEW_SPI_ZZ//发送数据,需配合写使能,片选操作。
static unsigned char spi_send_byte(unsigned char val)
{	while((GET_SPI(SPSR))&WFFULL);  //发送缓存满!!,等待SET_SPI(TXFIFO,val);while((GET_SPI(SPSR))&RFEMPTY); //等待发送结束return GET_SPI(RXFIFO); //读缓存
}
#endif///read status reg /int read_sr(void)
{int val;SET_SPI(SOFTCS,0x01);  //设置片选#ifdef NEW_SPI_ZZspi_send_byte(0x05);val = spi_send_byte(0x00);
#elseSET_SPI(TXFIFO,0x05);  //发送命令while((GET_SPI(SPSR))&RFEMPTY);  //等待发送结束val = GET_SPI(RXFIFO);  //读缓存SET_SPI(TXFIFO,0x00);	//写数据0,是为了读取一个数据while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY); //等待发送结束val = GET_SPI(RXFIFO); //读缓存
#endif	SET_SPI(SOFTCS,0x11);  //取消片选return val;
}#ifdef NEW_SPI_ZZ
static void spi_flash_check_busy(void)
{unsigned char res;do{res = read_sr();  //读flash状态寄存器}while((res&0x01));  //忙则继续等
}
#endifset write enable//
int set_wren(void)
{int res;#ifdef NEW_SPI_ZZ//spi_flash_check_busy();SET_SPI(SOFTCS,0x01);  //片选spi_send_byte(0x06);  //写使能	SET_SPI(SOFTCS,0x11);   //取消片选spi_flash_check_busy();return 1;
#else	res = read_sr();  //读flash状态寄存器while(res&0x01 == 1)  //忙则继续等{res = read_sr();  }SET_SPI(SOFTCS,0x01);  //片选SET_SPI(TXFIFO,0x6);    //发出命令0x6while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){  //等待发送接收}GET_SPI(RXFIFO);  //读接收缓存,数据丢掉SET_SPI(SOFTCS,0x11);   //取消片选return 1;
#endif
}///write status reg///
int write_sr(char val)
{int res;
#ifdef NEW_SPI_ZZset_wren(); //flash写使能操作//spi_flash_check_busy();SET_SPI(SOFTCS,0x01);  //片选spi_send_byte(0x01);  //写状态寄存器	spi_send_byte(val);  //写入值
#else	set_wren();	//flash写使能操作res = read_sr();  //读flash状态寄存器while(res&0x01 == 1)  //忙则继续等{res = read_sr();}SET_SPI(SOFTCS,0x01);  //片选SET_SPI(TXFIFO,0x01);  //发出命令0x1,这里是写发送缓存,写入发送缓存的数据,就会发送给flashwhile((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){ //读控制器的状态,读缓存为空吗?没收完整就是空     			}				//发送是串行的,数据写入缓存,到发送完是有个时间的。GET_SPI(RXFIFO);  //读接收缓存,数据丢掉SET_SPI(TXFIFO,val);  //再发送值,由参数传入while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){   //等待发送完    			}GET_SPI(RXFIFO);  //读接收缓存,数据丢掉
#endifSET_SPI(SOFTCS,0x11);  //取消片选return 1;	
}///erase all memory/
int erase_all(void)
{int res;int i=1;spi_initw();set_wren();res = read_sr();while(res&0x01 == 1){res = read_sr();}SET_SPI(SOFTCS,0x1);SET_SPI(TXFIFO,0xC7);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){      			}GET_SPI(RXFIFO);SET_SPI(SOFTCS,0x11);while(i++){if(read_sr() & 0x1 == 0x1){if(i % 10000 == 0)printf(".");}else{printf("done...\n");break;}   }return 1;
}void spi_read_id(void)
{unsigned char val;spi_initw();val = read_sr();while(val&0x01 == 1){val = read_sr();}/*CE 0*/SET_SPI(SOFTCS,0x01);/*READ ID CMD*/SET_SPI(TXFIFO,0x9f);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}GET_SPI(RXFIFO);/*Manufacturer’s ID*/SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);printf("Manufacturer's ID:         %x\n",val);/*Device ID:Memory Type*/SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);printf("Device ID-memory_type:     %x\n",val);/*Device ID:Memory Capacity*/SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);printf("Device ID-memory_capacity: %x\n",val);/*CE 1*/SET_SPI(SOFTCS,0x11);}#ifdef NEW_SPI_ZZ
#define PAGE_SIZE 0x100  //# 256B
//返回写入的字节数
static int spi_write_pagebytes(unsigned int addr,unsigned char *data,int len)
{unsigned int i = 0;//	printf("1 addr = %#x i = %u, len = %d data[0] = %hhx\n",addr,i,len,data[0]);if(len > PAGE_SIZE)len = PAGE_SIZE;   //最多一次编程1pagei = addr & (0xff);  //起始地址是不是256的整数倍if(len + i > PAGE_SIZE) //页内有偏移,从写入的位置开始,到结束不能超过页的边界len = PAGE_SIZE - i; //写入页内字节数//	printf("addr = %#x i = %u, len = %d data[0] = %hhx\n",addr,i,len,data[0]);//1. 写使能set_wren();//2 .片选,页编程命令SET_SPI(SOFTCS,0x01);/*CE 0*/spi_send_byte(0x02);  //写页编程指令//3. 发送地址spi_send_byte((addr)>>16);  //写地址spi_send_byte((addr)>>8);  //写地址spi_send_byte(addr);  //写地址//4. 发送数据for(i=0;i<len;i++){spi_send_byte(data[i]);  //写地址}//5.取消片选  /*CE 1*/SET_SPI(SOFTCS,0x11);  //取消片选spi_flash_check_busy(); //等待数据写入完成return len;   //返回实际写入的字节数
}//写入数据
static void spi_write_bytes(unsigned int addr,unsigned char *data,int len)
{int ret = 0;while(len>0){delay(3000);    //必须延时,否则写失败ret = spi_write_pagebytes(addr,data,len);  //返回写入了多少个字节//	printf("spi_write_bytes ret = %d\n",ret);addr+=ret;  //指针向后移动data+=ret;  //指针向后移动len -= ret;//	udelay(10000);    //必须延时,否则写失败//dotik(32, 0);			//显示旋转的字符}	
}
#endifvoid spi_write_byte(unsigned int addr,unsigned char data)
{
#ifdef NEW_SPI_ZZspi_write_pagebytes(addr,&data,1);
#else/*byte_program,CE 0, cmd 0x2,addr2,addr1,addr0,data in,CE 1*/unsigned char addr2,addr1,addr0;unsigned char val;addr2 = (addr & 0xff0000)>>16;addr1 = (addr & 0x00ff00)>>8;addr0 = (addr & 0x0000ff);set_wren();val = read_sr();while(val&0x01 == 1){val = read_sr();}SET_SPI(SOFTCS,0x01);/*CE 0*/SET_SPI(TXFIFO,0x2);/*byte_program */while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);/*send addr2*/SET_SPI(TXFIFO,addr2);     while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);/*send addr1*/SET_SPI(TXFIFO,addr1);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);/*send addr0*/SET_SPI(TXFIFO,addr0);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);/*send data(one byte)*/SET_SPI(TXFIFO,data);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}val = GET_SPI(RXFIFO);/*CE 1*/SET_SPI(SOFTCS,0x11);
#endif
}
// int write_pmon_byte(int argc,char ** argv)
// {
//     unsigned int addr;
//    unsigned char val; 
//     if(argc != 3){
//         printf("\nuse: write_pmon_byte  dst(flash addr) data\n");
//         return -1;
//     }
//     addr = strtoul(argv[1],0,0);
//     val = strtoul(argv[2],0,0);
//     spi_write_byte(addr,val);
// 	return 0;// }// int write_pmon(int argc,char **argv)
// {
// 	long int j=0;
//     unsigned char val;
//     unsigned int ramaddr,flashaddr,size;
// 	if(argc != 4){
//         printf("\nuse: write_pmon src(ram addr) dst(flash addr) size\n");
//         return -1;
//     }//     ramaddr = strtoul(argv[1],0,0);
//     flashaddr = strtoul(argv[2],0,0);
//     size = strtoul(argv[3],0,0);// 	spi_initw();
//     write_sr(0);
// // read flash id command
//     spi_read_id();
// 	val = GET_SPI(SPSR);
// 	printf("====spsr value:%x\n",val);// 	SET_SPI(0x5,0x10);
// // erase the flash     
// 	write_sr(0x00);
// //	erase_all();
//     printf("\nfrom ram 0x%08x  to flash 0x%08x size 0x%08x \n\nprogramming            ",ramaddr,flashaddr,size);
//     for(j=0;size > 0;flashaddr++,ramaddr++,size--,j++)
//     {
//         spi_write_byte(flashaddr,*((unsigned char*)ramaddr));
//         if(j % 0x1000 == 0)
//             printf("\b\b\b\b\b\b\b\b\b\b0x%08x",j);
//     }
//     printf("\b\b\b\b\b\b\b\b\b\b0x%08x end...\n",j);//     SET_SPI(0x5,0x11);
// 	return 1;
// }int read_pmon_byte(unsigned int addr,unsigned int num)
{unsigned char val,data;val = read_sr();while(val&0x01 == 1){val = read_sr();}SET_SPI(0x5,0x01);
// read flash command SET_SPI(TXFIFO,0x03);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}GET_SPI(RXFIFO);// addrSET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}GET_SPI(RXFIFO);SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}GET_SPI(RXFIFO);SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}GET_SPI(RXFIFO);SET_SPI(TXFIFO,0x00);while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){}data = GET_SPI(RXFIFO);SET_SPI(0x5,0x11);return data;
}// int read_pmon(int argc,char **argv)
// {
// 	unsigned char addr2,addr1,addr0;
// 	unsigned char data;
// 	int val,base=0;
// 	int addr;
// 	int i;
//         if(argc != 3)
//         {
//             printf("\nuse: read_pmon addr(flash) size\n");
//             return -1;
//         }
//         addr = strtoul(argv[1],0,0);
//         i = strtoul(argv[2],0,0);
// 	spi_initw();
// 	val = read_sr();
// 	while(val&0x01 == 1)
// 	{
// 		val = read_sr();
// 	}// 	SET_SPI(0x5,0x01);
// // read flash command 
// 	SET_SPI(TXFIFO,0x03);
// 	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){// 	}
// 	GET_SPI(RXFIFO);// // addr
// 	SET_SPI(TXFIFO,((addr >> 16)&0xff));
// 	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){// 	}
//         GET_SPI(RXFIFO);// 	SET_SPI(TXFIFO,((addr >> 8)&0xff));
// 	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){// 	}
// 	GET_SPI(RXFIFO);// 	SET_SPI(TXFIFO,(addr & 0xff));
// 	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){// 	}
// 	GET_SPI(RXFIFO);
// // addr end//         printf("\n");
//         while(i--)
// 	{
// 		SET_SPI(TXFIFO,0x00);
// 		while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){// 		}
// 	        data = GET_SPI(RXFIFO);
//                 if(base % 16 == 0 ){
//                     printf("0x%08x    ",base);
//                 }
//                 printf("%02x ",data);
//                 if(base % 16 == 7)
//                     printf("  ");
//                 if(base % 16 == 15)
//                     printf("\n");
// 		base++;	
// 	}
//         printf("\n");
// 	return 1;// }int spi_erase_area(unsigned int saddr,unsigned int eaddr,unsigned sectorsize)
{unsigned int addr;spi_initw(); for(addr=saddr;addr<eaddr;addr+=sectorsize){SET_SPI(SOFTCS,0x11);set_wren();write_sr(0x00);while(read_sr()&1);set_wren();SET_SPI(SOFTCS,0x01);/* * 0x20 erase 4kbyte of memory array* 0x52 erase 32kbyte of memory array* 0xd8 erase 64kbyte of memory array                                                                                                           */SET_SPI(TXFIFO,0x20);while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,addr >> 16);while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,addr >> 8);while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,addr);while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(SOFTCS,0x11);while(read_sr()&1);}SET_SPI(SOFTCS,0x11);delay(10);return 0;
}int spi_write_area(int flashaddr,char *buffer,int size)
{int j;spi_initw();    //spi控制设置为写模式
//	SET_SPI(0x5,0x10); //spi控制器,设置片选,输出低,低有效write_sr(0x00);  //写flash的状态寄存器,不是控制器的
#ifdef NEW_SPI_ZZspi_write_bytes(flashaddr,buffer,size);
#elsefor(j=0;size > 0;flashaddr++,size--,j++){spi_write_byte(flashaddr,buffer[j]);   //写入数据,一个字节一个字节dotik(32, 0);			//延时}
#endif
//	SET_SPI(SOFTCS,0x11); //取消片选,之前写入的数据是先到flash的缓存,然后才会编程到flash中,这样速度快一些delay(10);	//延时,结束,写入数据之后,flash会忙一阵子(把缓存的数据编程到flash中去)return 0;
}int spi_read_area(int flashaddr,char *buffer,int size)
{int i;spi_initw();SET_SPI(SOFTCS,0x01);SET_SPI(TXFIFO,0x03);while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,flashaddr>>16);     while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,flashaddr>>8);     while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);SET_SPI(TXFIFO,flashaddr);     while((GET_SPI(SPSR))&RFEMPTY);GET_SPI(RXFIFO);for(i=0;i<size;i++){SET_SPI(TXFIFO,0);     while((GET_SPI(SPSR))&RFEMPTY);buffer[i] = GET_SPI(RXFIFO);}SET_SPI(SOFTCS,0x11);delay(10);return 0;
}//off 就是flash内部的偏移地址
int fl_erase_device(int off, int size, int verbose)
{//struct fl_map *map;//int off = (int)fl_base;//map = fl_find_map(fl_base);//off = (int)(fl_base - map->fl_map_base) + map->fl_map_offset;spi_erase_area(off,off+size,0x1000);spi_initr();return 0;
}//off 就是flash内部的偏移地址
int fl_program_device(int off, void *data_base, int data_size, int verbose)
{//struct fl_map *map;//int off = (int)fl_base;//map = fl_find_map(fl_base);//off = (int)(fl_base - map->fl_map_base) + map->fl_map_offset;spi_write_area(off,data_base,data_size);spi_initr();return 0;
}// off 是flash中的偏移地址,起始地址0
// data_base 是文件内容的缓存起始地址
// data_size 是需要比较的数据大小
// verbose 是否打印信息
int fl_verify_device(int off, void *data_base, int data_size, int verbose)
{int ok = 0;int i;if(data_size == -1 || data_base == NULL) {printf("fl_verify_device : data_size == -1 || data_base == NULL\n");return(-4);		/* Bad parameters */}if((data_size + off) > 0x100000) {    //大于1m不行printf("fl_verify_device : (data_size + off) > 0x100000\n");return(-4);	/* Size larger than device array */}if(verbose) {printf("Verifying FLASH. ");}//直接用文件与映射的地址if(memcmp(data_base,spi_mem_base_addr+off,data_size) == 0)ok = 1;elseprintf("fl_verify_device with error!!\n");if(verbose && ok) {printf("\b No Errors found.\n");}return(ok);
}//p 表示 flash 内部的起始地址,从0开始算,小于1MB
//size 表示字节数
//s 表示要写入的内容缓存起始地址
void tgt_flashprogram(int p, int size, void *s)
{printf("Programming flash %x:%x into %x\n", s, size, p);if (fl_erase_device(p, size, TRUE)) {printf("Erase failed!\n");return;}printf("Erase done!!\n");if (fl_program_device(p, s, size, TRUE)) {printf("Programming failed!\n");}printf("Program done!!\n");fl_verify_device(p, s, size, TRUE);printf("Verify done!!\n");
}

makefile ,注意要设置一下编译环境

CC= mips64el-loongson-linux-gccall: mymap.o spi_w.o$(CC) --static  -o  program_pmon_ls2k1000 $^%.o:%.c$(CC) -c $^clean:rm -f program_pmon_ls2k1000 *.o

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/733271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络工程师笔记10 ( RIP / OSPF协议 )

RIP 学习路由信息的时候需要配认证 RIP规定超过15跳认定网络不可达 链路状态路由协议-OSPF 1. 产生lsa 2. 生成LSDB数据库 3. 进行spf算法&#xff0c;生成最有最短路径 4. 得出路由表

【探索C++容器:set和map的使用】

[本节目标] 1. 关联式容器 2. 键值对 3. 树形结构的关联式容器 1. 关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为…

Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)(A~C)

A - Spoiler 竖线里面的不要输出&#xff0c;竖线只有一对&#xff0c;且出现一次。 #include <bits/stdc.h> //#define int long long #define per(i,j,k) for(int (i)(j);(i)<(k);(i)) #define rep(i,j,k) for(int (i)(j);(i)>(k);--(i)) #define debug(a) cou…

链表|面试题 02.07.链表相交

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode *l NULL, *s NULL;int lenA 0, lenB 0, gap 0;// 求出两个链表的长度s headA;while (s) {lenA ;s s->next;}s headB;while (s) {lenB ;s s->next;}// 求出两个链表长度差if (lenA &…

stm32学习笔记:SPI通信协议原理(未完)

一、SPI简介(serial Peripheral Interface&#xff08;串行 外设 接口&#xff09;) 1、电路模式&#xff08;采用一主多从的模式&#xff09;、同步&#xff0c;全双工 1 所有SPI设备的SCK、MOSI、MISO分别连在一起 2 主机另外引出多条SS控制线&#xff0c;分别接到各从机的S…

DetNet论文速读

paper&#xff1a;DetNet: A Backbone network for Object Detection 存在的问题 最近的目标检测模型通常依赖于在ImageNet分类数据集上预训练的骨干网络。由于ImageNet的分类任务不同于目标检测&#xff0c;后者不仅需要识别对象的类别&#xff0c;而且需要对边界框进行空间…

音视频开发_音频基础知识

如何采集声音——模数转换原理 声音模数转换是将声音信号从模拟形式转换为数字形式的过程。它是数字声音处理的基础&#xff0c;常用于语音识别、音频编码等应用中。 音视频通信流程 音视频采集&#xff1a;首先是从麦克风、摄像头等设备中采集音频和视频数据&#xff0c;将现…

【Windows】VMware虚拟机应用(一):下载安装 VMware Workstation

目录 一、下载 二、注意事项 三、安装 四、密钥激活 4.1 密钥 4.2 激活 一、下载 进入官网下载页 VMware Customer Connect | The All-In-One VMware Product Support Portal 先登录&#xff0c;下载时要求登录。 点【Downloads】 进入产品下载页面&#xff0c;切换到…

手写简易操作系统(三)--加载Loader

前情提要 上一节我们讲了如何启动计算机&#xff0c;这一节我们讲如何加载内核&#xff0c;内核是存在于硬盘上的一段程序&#xff0c;要加载这段程序&#xff0c;那么必然需要从硬盘上读取数据&#xff0c;这里我们就需要使用 ATA PIO 模式 根据ATA规范&#xff0c;所有符合A…

docker部署springboot jar包项目

docker部署springboot jar包项目 前提&#xff0c;服务器环境是docker环境&#xff0c;如果服务器没有安装docker&#xff0c;可以先安装docker环境。 各个环境安装docker&#xff1a; Ubuntu上安装Docker&#xff1a; ubuntu离线安装docker: CentOS7离线安装Docker&#xff1…

可视化场景(2):电商大屏-引爆业绩,直观呈现

hello&#xff0c;我是贝格前端工场&#xff0c;本期分享可视化大屏在电商领域的应用&#xff0c;如需要定制&#xff0c;可以与我们联络&#xff0c;开始了。 电商领域的可视化大屏可以提供实时的销售数据、用户行为分析、库存管理等信息&#xff0c;帮助企业实时监控经营状况…

不知道吧,腾讯云轻量应用服务器使用有一些限制!

腾讯云轻量应用服务器相对于云服务器CVM是有一些限制的&#xff0c;比如轻量服务器不支持更换内网IP地址&#xff0c;不支持自定义私有网络VPC&#xff0c;内网连通性方面也有限制&#xff0c;轻量不支持CPU内存、带宽或系统盘单独升级&#xff0c;只能整个套餐整体升级&#x…

Anthropic 公司最新宣布,他们的 AI 聊天机器人模型击败了 OpenAI 的 GPT-4

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Unity Text文本实现滚动跑马灯效果

在一些公告上我们经常会看到文字滚动跑马灯的效果。 那么在Unity上如何实现&#xff1f; 1、首先创建一个Text(或者TextMeshPro)组件&#xff0c;然后输入需要显示的文本内容&#xff0c;如图&#xff1a; 2、编写控制脚本TextRoll.cs&#xff1a; using System.Collections…

钉钉h5应用 globalthis is not defined vite client

钉钉h5应用 globalthis is not defined vite client problem 背景 钉钉h5应用使用 vue3 vite 构建的前端工程 问题 h5页面在pc端浏览器和pc端钉钉打开正常h5页面在移动端钉钉打开异常 页面空白 通过调试工具找到报错信息 globalthis is not defined vite client reason …

ULTRAL SCALE FPGA TRANSCEIVER速率

CPLL支持2-6.25速率 QPLL支持速率 实际使用CPLL最高可以超过这个&#xff0c;QPLL最低也可以低于这个&#xff0c;xilinx留的阈量还是比较大。

这是谁的女儿?其母亲早已红过头了,现在小小年纪的她也爆红网络,没想到吧?

这是谁的女儿&#xff1f;其母亲早已红过头了&#xff0c;现在小小年纪的她也爆红网络&#xff0c;没想到吧&#xff1f; 原来&#xff0c;作母亲的她在红极一时后似乎沉寂了下来&#xff0c;没想到她11岁的女儿近年来也在社交媒体上走红&#xff0c;她为何也成了小网红呢&…

数字化转型导师坚鹏:大模型的应用实践(金融)

大模型的应用实践 ——开启人类AI新纪元 打造数字化转型新利器 课程背景&#xff1a; 很多企业和员工存在以下问题&#xff1a; 不清楚大模型对我们有什么影响&#xff1f; 不知道大模型的发展现状及作用&#xff1f; 不知道大模型的针对性应用案例&#xff1f; 课程…

C# 高级特性(十一):多线程之async,await

之前使用Thread和Task启动多线程时都会遇到一个麻烦&#xff0c;就是如何反馈结果。在代码里就是如何设计回调函数。如果带界面还得考虑UI线程的问题。 而使用async&#xff0c;await可以达到两个效果。 1 不用设计回调函数&#xff0c;直接按单线程的格式写。 2 不用考虑UI…

【决策树】预测用户用电量

决策树预测用户用电量 文章目录 决策树预测用户用电量  &#x1f449;引言&#x1f48e;一、 数据预处理数据预处理初步数据分析 二、 机器学习算法决策树回归预测用电量决策树模型介绍&#xff1a;回归预测 三、 可视化结果四、 数据分析与结论代码如下 &#x1f449;引言&a…