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个字节留出来做校验和,最大不能超过16k
	gzrom的起始位置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 0x500000



void 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 flash
		filename = 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;//1M


    PAGE_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; //4K
    spireg_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);   //起始地址是0
		printf("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_ZZ


static 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:0100
 	SET_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_ZZ
	spi_send_byte(0x05);
	val = spi_send_byte(0x00);
#else
	SET_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));  //忙则继续等
}
#endif


set 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);    //发出命令0x6
       	while((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_ZZ
	set_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,这里是写发送缓存,写入发送缓存的数据,就会发送给flash
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){ //读控制器的状态,读缓存为空吗?没收完整就是空     			
	}				//发送是串行的,数据写入缓存,到发送完是有个时间的。
	GET_SPI(RXFIFO);  //读接收缓存,数据丢掉

	SET_SPI(TXFIFO,val);  //再发送值,由参数传入
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){   //等待发送完    			
	}
	GET_SPI(RXFIFO);  //读接收缓存,数据丢掉
#endif
	SET_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;   //最多一次编程1page

	i = 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);			//显示旋转的字符
	}	
}
#endif

void spi_write_byte(unsigned int addr,unsigned char data)
{
#ifdef NEW_SPI_ZZ
	spi_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);
	
// addr
	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){
      			
	}
	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_ZZ
	spi_write_bytes(flashaddr,buffer,size);
#else
    for(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;
	else
		printf("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-gcc

all: mymap.o spi_w.o
	$(CC) --static  -o  program_pmon_ls2k1000 $^

%.o:%.c
	$(CC) -c $^


clean:
	rm -f program_pmon_ls2k1000 *.o

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何开通 GitHub Sponsors

Github Sponsors 是什么&#xff1f; 简单来说&#xff0c;GitHub Sponsors 是一个赞助服务&#xff0c;它允许个人和组织直接向开源贡献者和项目提供财务赞助&#xff0c;以便于有更多的时间和资源来专注于自己的开源工作。 这对于开源贡献者来说是非常棒&#x1f389;的&…

Swift 入门学习:集合(Collection)类型趣谈-下

概览 集合的概念在任何编程语言中都占有重要的位置&#xff0c;正所谓&#xff1a;“古来聚散地&#xff0c;宿昔长荆棘&#xff1b;游人聚散中&#xff0c;一片湖光里”。把那一片片、一瓣瓣、一粒粒“可耐”的小精灵全部收拢、吸纳的井然有序、条条有理&#xff0c;怎能不让…

008-slot插槽

slot插槽 1、插槽 slot 的简单使用2、插槽分类2.1 默认插槽2.2 具名插槽2.3 作用域插槽 插槽就是子组件中的提供给父组件使用的一个占位符&#xff0c;用<slot></slot> 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&…

【Docker】容器的生态系统

Docker提供了一整套技术支持&#xff0c;包括核心技术、平台技术、支持技术。 核心技术 容器核心技术是指能让Container&#xff08;容器&#xff09;在host&#xff08;集群、主机&#xff09;上运行起来的那些技术。 1&#xff09;容器规范&#xff1a;OCI&#xff08;runt…

round四舍五入在python2与python3版本间区别

round()方法返回数值的小数点四舍五入到n个数字。 语法 以下是round()方法的语法&#xff1a; round( x ,n) 参数 x --这是一个数值&#xff0c;表示需要格式化的数值 n --这也是一个数值,表示小数点后保留多少位 返回值 该方法返回 数值x 的小数点四舍五入到n个数字 …

计算机设计大赛 疲劳驾驶检测系统 python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#x…

图|dfs bfs|最小生成树|最短路|一篇搞定图的所有知识点

文章目录 图前言项目代码仓库图的基本概念图的表示方法邻接矩阵邻接表图的一些相关概念 图的遍历bfsdfs如果给的图不是连通图&#xff1f; 最小生成树Kruskal算法Prim算法 最短路径单源最短路径--Dijkstra算法单源最短路径--Bellman-Ford算法多源最短路径--Floyd-Warshall算法 …

数据治理实践——YY 直播业务指标治理实践

目录 一、问题背景 1.1 问题场景 1.2 问题小结 二、治理方案 2.1 治理目标 2.2 团队协同&#xff0c;共建规范 2.3 指标管理的定位 2.4 指标管理的目标及思路 2.5 指标管理&#xff0c;规范内容落地 2.6 数仓设计-关联指标维度 2.7 数据报表开发-配置口径说明 2.8 …

MongoDB在Linux环境下的安装与配置

目录 1. 准备工作 2. 安装MongoDB 2.1 传输MongoDB安装包 2.2 解压安装包 2.3 创建MongoDB安装目录 2.4 创建数据目录和日志目录 3. 启动MongoDB服务 3.1 启动MongoDB 3.2 连接MongoDB 3.3 退出MongoDB 1. 准备工作 在安装MongoDB之前&#xff0c;请确保您已具备以下…

Solidity Uniswap V2 价格预言机

预言机是连接区块链与链下服务的桥梁&#xff0c;这样就可以从智能合约中查询现实世界的数据。Chainlink 是最大的oracle网络之一&#xff0c;创建于 2017 年&#xff0c;如今已成为许多 DeFi 应用的重要组成部分。https://github.com/XuHugo/solidityproject Uniswap 虽然是链…

【leetcode热题】寻找旋转排序数组中的最小值 II

难度&#xff1a; 困难通过率&#xff1a; 38.7%题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如&#xff0c;数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 请找出其中最小的…

【react框架】跟我一起速读Next.js官方入门教学课程文档

文章目录 前言目录结构样式方案正常引入样式文件Tailwind方案CSS Modules方案clsx方案 文字和图片优化文字图片 Pages和Layout的机制PagesLayout 通过Link组件改变路由并且拆分打包提供Hooks通过Vercel创建数据未完待续... 前言 对于那些对Next.js一无所知的前端伙伴来说&…

鸿蒙开发(二)-项目结构

鸿蒙开发(二)-项目结构 上篇文章我们讲了如何配置鸿蒙开发的基础环境&#xff0c;以及创建了第一个鸿蒙程序。 这篇我们讲述了鸿蒙应用的项目目录结构。 如图所示&#xff1a;我们切换项目project可以看到。 另一种则是Ohos模式: AppScope->app.json5 应用的全局配置 {&q…

华为新发布磁电存储“王炸”,到底是什么?

最近&#xff0c;在巴塞罗那举行的2024年世界移动通信大会&#xff08;MWC24&#xff09;上&#xff0c;华为数据存储产品线总裁周彼得博士介绍了这款即将面世的产品。他向听众表示&#xff0c;与磁带存储相比&#xff0c;该设备可以降低20%的总连接成本&#xff0c;而与硬盘相…

DHCP中继实验(华为)

思科设备参考&#xff1a; 一&#xff0c;技术简介 DHCP中继&#xff0c;可以实现在不同子网和物理网段之间处理和转发DHCP信息的功能。如果DHCP客户机与DHCP服务器在同一个物理网段&#xff0c;则客户机可以正确地获得动态分配的IP地址。如果不在同一个物理网段&#xff0c;…

Web渗透测试流程

什么是渗透测试 渗透测试 (penetration test),是通过模拟恶意黑客的攻击方法&#xff0c;来评估计算机网络系统安全的一种评估方法。这个过程包括对系统的任何弱点、技术缺陷或漏洞的主动分析&#xff0c;这个分析是从一个攻击者可能存在的位置来进行的&#xff0c;并且从这个…

机器学习第29周周报 Beyond Dropout

文章目录 week29 Beyond Dropout摘要Abstract一、泛化理论二、文献阅读1. 题目2. abstract3. 网络架构3.1 特征图失真3.2 失真优化 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 全连接层实验4.3.2 卷积网络上的实验 4.4 结论 小结参考文献 week29 Beyond Dropout …

国产硅片膜厚检测仪

硅片膜厚检测仪是半导体行业中一种至关重要的设备&#xff0c;用于精确测量硅片上薄膜的厚度。在半导体制造工艺中&#xff0c;薄膜厚度的控制对于保证器件性能和可靠性具有决定性的作用。因此&#xff0c;硅片膜厚检测仪的研发和应用对于推动半导体技术的发展具有重要意义。 一…

SSM框架,MyBatis-Plus的学习(下)

条件构造器 使用MyBatis-Plus的条件构造器&#xff0c;可以构建灵活高效的查询条件&#xff0c;可以通过链式调用来组合多个条件。 条件构造器的继承结构 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xf…

苍穹外卖-day01

苍穹外卖-day01 目录 苍穹外卖-day01课程内容1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 产品原型2.3 技术选型 3. 开发环境搭建3.1 前端环境搭建3.2 后端环境搭建3.2.1 熟悉项目结构3.2.2 Git版本控制3.2.3 数据库环境…
最新文章