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…

设计模式 工厂模式

工厂模式&#xff0c;最重要的是反射。 反射&#xff1a;Class类 java的注释是这样写的&#xff1a; Class没有公共构造函数。相反&#xff0c;Class对象是在类加载时由Java虚拟机自动构造的&#xff0c;并通过调用类加载器中的defineClass方法来实现。

链表|面试题 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 &…

LeetCode刷题笔记之动态规划(一)

一、动态规划的基础知识 动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;&#xff0c;动态规划问题的一般形式就是求最值&#xff0c;求解动态规划的核心问题是穷举&#xff0c;动态规划中每一个状态一定是由上一个状态推导出来的。解题步骤&#xff…

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;将现…

编写Linux的SHELL脚本设置环境变量遇到的那些坑

1.背景 最近进行一个rocketmq的单机版安装&#xff0c;发现安装步骤很繁琐&#xff0c;想着写一个shell脚本&#xff0c;一键执行安装。 本文仅在于说明关于JDK的环境变量设置为示例 2.SHELL脚本设置环境变量 #!/bin/sh #定义变量 profile_file~/.bash_profile #1.安装JDK t…

SQL之常用字符串函数

1. LOWER( )&#xff1a;将字符串中的所有字符转换为小写。 select lower(Hello World); -- 输出&#xff1a;hello world 2. UPPER( )&#xff1a;将字符串中的所有字符转换为大写。 select upper(Hello World); -- 输出&#xff1a;HELLO WORLD 3. CONCAT( )&#xff…

【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…

深度学习的一些工具函数

文章目录 简介数据集划分数据集 简介 记录深度学习编写程序过程中的一些工具函数 数据集 划分数据集 数据集划分思路&#xff1a; 若数据集很小&#xff0c;直接随机打乱 import random random.shuffle(data)若数据集很大&#xff0c;选择随机打乱下标&#xff0c;根据下…

docker部署springboot jar包项目

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

算法-排序

0、复杂度及稳定性 时间复杂度空间复杂度 稳定性&#xff08;相等元素相对顺序不变&#xff09; 冒泡排序 时间复杂度为O(n^2) 最坏/平均&#xff1a;O(n^2) 最好&#xff1a;O(n)&#xff0c;序列有序 O(1)稳定插入排序 时间复杂度为O(n^2) 最坏/平均&#xff1a;O(n^2) 最好…

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

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

java jdk17 HashMap解读

类描述 基于Hash表的Map接口实现。此实现提供了所有的可选的map操作&#xff0c;并且避免了null值和null键。&#xff08;HashMap类大体上等价于Hashtable,除了它是非同步的和禁止null&#xff09;。此类不保证map的顺序。特别是&#xff0c;不保证随着时间的变化顺序保持不变…

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

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

题目 2021: 坐标排序

题目描述: 请将坐标x,y,z依照以下规则排序&#xff1a; x为第一关键字&#xff0c;当x相同时&#xff0c;依照y&#xff08;第二关键字&#xff09;大小来排序&#xff0c;当y相同时&#xff0c;依照z大小来排序&#xff08;第三关键字&#xff09; 给出了若干坐标&#xff0c…