VS1000/VSMD001 bootloader

Writing software that controls the system and peripherals such as displays, SD cards, Buttons, LEDs, Serial Ports etc.
Post Reply
Oni
User
Posts: 5
Joined: Thu 2016-10-13 15:58

VS1000/VSMD001 bootloader

Post by Oni »

Hi,

I am using the VSMD001 and I modified the default firmware (VS1000AudioModule-072-VSIDE.zip) to my needs. At start (VCC on) the firmware is being loaded throug spi-bus from the flash and than gets executed.
My question is - where is the procedure of loading the firmware through spi implemented? Can I change it? If yes, how and where?

I found a post from Panu saying this: "The reason ( :o ) is that for IC production test reasons, the bootloader must also work in a chip that has a broken RAM. That's why the bootloader is written in assembler, never reads from RAM (only uses registers) and is kept as simple as possible. "

Can you help me?
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Re: VS1000/VSMD001 bootloader

Post by Panu »

The bootloader is in ROM, it cannot be changed.

That said, what are you trying to accomplish, exactly? There's severe RAM constrictions in VS1000 (only 8 kilobytes of program RAM) so the module software is a multiload-software, e.g. the program which is loaded in RAM is changed based on in which mode the program is. That's one of the ways to overcommit memory.

-Panu
Oni
User
Posts: 5
Joined: Thu 2016-10-13 15:58

Re: VS1000/VSMD001 bootloader

Post by Oni »

There are 2 things I would like to achieve - the audio module is a part of a bigger circuitry:
1. There is a hardware watchdog which I would like to clock (through an GPIO0_x) during the flashing of the audio module with new firmware, so it does not reset and I do not have to remove the module for flashing (now works only without the watchdog)
2. And there is also a bus buffer IC (for achieving a high impendance state of an spi-MISO output of an shift register) which should be set to high through an GPIO0_x during the firmware upload/boot (in the firmware I'm handling it myself) - now it seems to work only reliable, when the watchdog is in the circuit (probably it resets the board until everything is loaded properly), otherwise somtimes the board does not load the firmware and hangs at the very beginning.
User avatar
pasi
VLSI Staff
Posts: 2122
Joined: Thu 2010-07-15 16:04

Re: VS1000/VSMD001 bootloader

Post by pasi »

1. How is the flashing performed? If it's from the SD card, then sdupdate.c needs to be changed.

2. You can insert a memory write record into the boot image (usbmass which is loaded first) using the -d option of coff2allboot. You can perform the suitable GPIO0_MODE, GPIO0_DDR and GPIO0_ODATA writes using that.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
Oni
User
Posts: 5
Joined: Thu 2016-10-13 15:58

Re: VS1000/VSMD001 bootloader

Post by Oni »

First, thanks for the fast answers - it is a really great support here.

1. The flashing is performed through VSIDE+UART (with xcs put to GND first for 3 seconds)

2. The Firmware has been modified and now there is only the SD-Player part (no usb, no flash player... no spiload). I'm playing ogg files, gapless, some of them in loop... vsmd001 is really a nice piece of hardware. In my GpioInit()- Function I'm setting the out- and inputs and configure the output states.

The memory write idea sounds very interesting, but I never have done that before. Can you please give me an (code) example for this? Thanks in advance.
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Re: VS1000/VSMD001 bootloader

Post by Panu »

Here's a coff2allboot command line option to set all bits in GPIO0_MODE to zero. You can add several -d options.

Code: Select all

 -d x:0xC010=0x0000
In reality, this approach is difficult since you need to know exactly what you are doing because you need to set the modes of all pins (there's no ORin or ANDing possible).


Hmm, the proper fix would be to modify the prommer, but I didn't find the source code of uniprom1k24 :o
But I think I know where it is, I'll dig it up, then you can modify the prommer to include the necessary IO writes.

-Panu
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Re: VS1000/VSMD001 bootloader

Post by Panu »

Hi!

Finally found the source code for uniprom1k24, the VS1000 spi flash prommer module included in VSIDE. This code compiles with the old VSKIT 1.34 command line tools, in vskit subfolder "vs1000bc". Obviously it can be compiled also in VSIDE with a suitable solution setup...

The idea is that you can add your GPIO writes here, directly into the prommer, and then compile it into uniprom1k24.coff and overwrite the one in VSIDE, or compile it to another coff file name such as uniprom1k24_oni.coff and then insert a new entry to vside\bin\prommer.index that uses your coff. The next time you boot VSIDE, your prommer will be listed in VSIDE.

Source code of UNIPROM1K24:

Code: Select all

// PROMMER for 24-bit addressable flashes like the INTEL S33,
// EON and WINBOND 128kilobyte...16megabyte SPI flashes
// uniprom1k24.c

#include <stdio.h>

#include <string.h>
#include <stdlib.h>
#include <vs1000.h>
#include <audio.h>
#include <mappertiny.h>
#include <minifat.h>
#include <physical.h>
#include <vsNand.h>

#include <codec.h>
#include <player.h>
//#include "system.h"

#define RESERVED_BLOCKS 32

__y const char hex[] = "0123456789abcdef";

void puthex(u_int16 a) {
	char tmp[8];
	tmp[0] = hex[(a>>12)&15];
	tmp[1] = hex[(a>>8)&15];
	tmp[2] = hex[(a>>4)&15];
	tmp[3] = hex[(a>>0)&15];
	tmp[4] = ' ';
	tmp[5] = '\0';
	fputs(tmp, stdout);
}

void put2c(u_int16 a) {
	char tmp[8];
	tmp[0] = a>>8;
	tmp[1] = a&0xff;
	if (tmp[0]<32) tmp[0]='.';
	if (tmp[1]<32) tmp[1]='.';
	if (tmp[0]>127) tmp[0]='.';
	if (tmp[1]>127) tmp[1]='.';
	tmp[2] = '\0';
	fputs(tmp, stdout);
}

void put2hex(u_int16 a) {
	char tmp[8];
	tmp[0] = hex[(a>>12)&15];
	tmp[1] = hex[(a>>8)&15];
	tmp[2] = ' ';
	tmp[3] = hex[(a>>4)&15];
	tmp[4] = hex[(a>>0)&15];
	tmp[5] = ' ';
	tmp[6] = '\0';
	fputs(tmp, stdout);
}

extern struct FsPhysical *ph;
extern struct FsMapper *map;
extern __y u_int16 mallocAreaY[]; /* for ramdisk */
extern u_int16 mallocAreaX[];			/* for ramboot */
void SpiLoad(register __i2 short startAddr, register __i0 short m24);

#define SPI_EEPROM_COMMAND_WRITE_ENABLE	 0x06
#define SPI_EEPROM_COMMAND_WRITE_DISABLE	0x04
#define SPI_EEPROM_COMMAND_READ_STATUS_REGISTER	 0x05
#define SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER	0x01
#define SPI_EEPROM_COMMAND_READ	 0x03
#define SPI_EEPROM_COMMAND_WRITE 0x02
#define SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS 0x30
#define SPI_EEPROM_COMMAND_ERASE_SECTOR 0xD8
#define SPI_EEPROM_COMMAND_ERASE_4K_SECTOR 0x20

//MASTER, 8BIT, FSYNC PIN IDLE=1
#define SPI_MASTER_8BIT_CSHI	 PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN8 | SPI_CF_FSIDLE1
//MASTER, 8BIT, FSYNC PIN IDLE=0 (makes /CS)
#define SPI_MASTER_8BIT_CSLO	 PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN8 | SPI_CF_FSIDLE0
//MASTER, 16BIT, FSYNC PIN IDLE=0 (makes /CS)
#define SPI_MASTER_16BIT_CSLO	 PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN16 | SPI_CF_FSIDLE0

void SingleCycleCommand(u_int16 cmd){
	SPI_MASTER_8BIT_CSHI; 
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(cmd);
	SPI_MASTER_8BIT_CSHI;
}

/// Wait for not_busy (status[0] = 0) and return status
u_int16 SpiWaitStatus(void) {
	u_int16 status;
	SPI_MASTER_8BIT_CSHI;
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_READ_STATUS_REGISTER);
	while ((status = SpiSendReceive(0)) & 0x01){
		// puthex(status);puts("=status");
	}
	; //Wait until ready
	SPI_MASTER_8BIT_CSHI;
	return status;
}

u_int16 SpiReadBlock(u_int16 blockn, u_int16 *dptr) {
	SpiWaitStatus();
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_READ);
	SpiSendReceive(blockn>>7);						// Address[23:16] = blockn[14:7]
	SpiSendReceive((blockn<<1)&0xff);			// Address[15:8]	= blockn[6:0]0
	SpiSendReceive(0x00);									// Address[7:0]	 = 00000000
	SPI_MASTER_16BIT_CSLO;
	{
		int n;
		for (n=0; n<256; n++){
			*dptr++ = SpiSendReceive(0);
		}
	}
	SPI_MASTER_8BIT_CSHI;
	return 0;
}

u_int16 SpiVerifyBlock(u_int16 blockn, u_int16 *dptr) {
	SpiWaitStatus();
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_READ);
	SpiSendReceive(blockn>>7);						// Address[23:16] = blockn[14:7]
	SpiSendReceive((blockn<<1)&0xff);			// Address[15:8]	= blockn[6:0]0
	SpiSendReceive(0x00);										 // Address[7:0]	 = 00000000
	SPI_MASTER_16BIT_CSLO;
	{
		int n;
		for(n=0;n<256;n++) {
			if(*dptr++!=SpiSendReceive(0)) {
				SPI_MASTER_8BIT_CSHI;
				return 1;
			}
		}
	}
	SPI_MASTER_8BIT_CSHI;
	return 0;
}

/// Write a block to EEPROM. Caution: Does not erase block
/// \param blockn number of sector to write: 0..32767 (16Mbytes)
/// \param dptr pointer to data block

u_int16 SpiWriteBlock(u_int16 blockn, u_int16 *dptr) {
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
	SingleCycleCommand(SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS);
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
	SpiSendReceive(0x02); //Sector Protections Off
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_WRITE);
	SpiSendReceive(blockn>>7);						// Address[23:16] = blockn[14:7]
	SpiSendReceive((blockn<<1)&0xff);			// Address[15:8]	= blockn[6:0]0
	SpiSendReceive(0);										// Address[7:0]		= 00000000
	SPI_MASTER_16BIT_CSLO;
	{
		u_int16 n;
		for (n=0; n<128; n++){
			SpiSendReceive(*dptr++);
		}
	}
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_WRITE);
	SpiSendReceive(blockn>>7);			 
	SpiSendReceive(((blockn<<1)+1)&0xff); // Address[15:8]	= blockn[6:0]1
	SpiSendReceive(0);							
	SPI_MASTER_16BIT_CSLO;
	{
		int n;
		for (n=128; n<256; n++){
			SpiSendReceive(*dptr++);
		}
	}
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
	return 0;
}


/// Erase one erasable block
/// Erase size for intel flash: 64K (128 disk sectors)

void SpiEraseBlock(u_int16 blockn_inside_sector){
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);	
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
	SpiSendReceive(0x02); //Sector Protections Off
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);	
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_ERASE_SECTOR);
	SpiSendReceive(blockn_inside_sector>>7);			 
	SpiSendReceive((blockn_inside_sector<<1)&0xff);
	SpiSendReceive(0);							
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
}

void Prom_vs1000img() {
	u_int16 len;
	u_int16 sectorNumber=0;
	FILE* fp;
	fp=fopen("eeprom.img","rb");
	if(!fp) {
		puts("Error: eeprom.img was not found");
		return;
	}
	puts("Programming eeprom.img. This does not erase old image.");
	PERIP(INT_ENABLEL)&=~INTF_RX;
	Disable();
	while((len=fread(minifatBuffer,1,256,fp))) {
		//Enable();
		SpiWriteBlock(sectorNumber,minifatBuffer);
		if(SpiVerifyBlock(sectorNumber,minifatBuffer)){
			puts("Verify Error. You may need to erase chip.");
			PERIP(INT_ENABLEL) |= INTF_RX;
			fclose(fp);
			return;
		}
		sectorNumber++;
		puthex(sectorNumber);
		Disable();
	}
	Enable();
	PERIP(INT_ENABLEL)|=INTF_RX;
	fclose(fp);
	puts("Done.");
}

void EeUnprotect() {
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
	SPI_MASTER_8BIT_CSLO;
	SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
	SpiSendReceive(0x02); //Sector Protections Off
	SPI_MASTER_8BIT_CSHI;
	SpiWaitStatus();
	SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
}

void Erase4kBlock(u_int16 blockn) {
		// Erase 4K sector
		SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
		SingleCycleCommand(SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS);
		EeUnprotect();
		SPI_MASTER_8BIT_CSLO;
		SpiSendReceive(SPI_EEPROM_COMMAND_ERASE_4K_SECTOR);
		SpiSendReceive(blockn>>7);						// Address[23:16] = blockn[14:7]
		SpiSendReceive((blockn<<1)&0xff);			// Address[15:8]	= blockn[6:0]0
		SpiSendReceive(0);										// Address[7:0]		= 00000000
		SPI_MASTER_8BIT_CSHI;
		SpiWaitStatus();
}

void main(void) {
	Disable(); // no interrupts allowed (experimental)
	// init spi
	SPI_MASTER_8BIT_CSHI;
	PERIP(SPI0_FSYNC)=0; 
	PERIP(SPI0_CLKCONFIG)=SPI_CC_CLKDIV*(2-1); //clock divider 2
	PERIP(GPIO1_MODE)|=0x1f; /* enable SPI pins */
	PERIP(INT_ENABLEL)&=~INTF_RX; // disable RX interrupt
	/* Make sure there is enough voltage to program the SPI memory. */
	if(voltages[voltIoPlayer]<18) {
			voltages[voltIoPlayer]=18; /*2.7*/
			PowerSetVoltages(&voltages[voltCorePlayer]);
	}
	puts("\nVS1000 SPI EEPROM Write Utility (uniprom1k24)");
	puts("Supports EEPROMS with 24bit address (128 kilobytes to 16 megabytes)\n");
	{
		long i=0;
		long size=0;
		FILE* f=fopen("eeprom.img","rb");
		if(f) {
			fseek(f,0,SEEK_END);
			size=ftell(f);
			fclose(f);
		} else {
			puts("eeprom.img not found");
			exit(-1);
		}
		puts("Erasing blocks:");
		while(i*512<size+511) {
			/* Only erase the firmware space */
			puthex(i);
			Erase4kBlock(i);
			i += 4;
		}
		puts("");
	}
	Prom_vs1000img();
	puts("Done. Reseting chip.");
	{ // Detach vs3emu
		int i;
		for (i=0;i<61;i++)
			putch(0x10);
			while ((USEX(UART_STATUS) & UART_ST_TXRUNNING))
			;
	}
	PERIP(WDOG_CONFIG)=2;
	PERIP(WDOG_RESET)=WDOG_RESET_VAL;
	while(1) {
		; // Wait for watchdog reset
	}
}


[/quote]



-Panu

[code]// PROMMER for 24-bit addressable flashes like the INTEL S33,
// EON and WINBOND 128kilobyte...16megabyte SPI flashes

#include <stdio.h>

#include <string.h>
#include <stdlib.h>
#include <vs1000.h>
#include <audio.h>
#include <mappertiny.h>
#include <minifat.h>
#include <physical.h>
#include <vsNand.h>

#include <codec.h>
#include <player.h>
#include "system.h"

//#define RESERVED_BLOCKS 32

__y const char hex[] = "0123456789abcdef";
void puthex(u_int16 a) {
  char tmp[8];
  tmp[0] = hex[(a>>12)&15];
  tmp[1] = hex[(a>>8)&15];
  tmp[2] = hex[(a>>4)&15];
  tmp[3] = hex[(a>>0)&15];
  tmp[4] = ' ';
  tmp[5] = '\0';
  fputs(tmp, stdout);
}

void put2c(u_int16 a) {
  char tmp[8];
  tmp[0] = a>>8;
  tmp[1] = a&0xff;
  if (tmp[0]<32) tmp[0]='.';
  if (tmp[1]<32) tmp[1]='.';
  if (tmp[0]>127) tmp[0]='.';
  if (tmp[1]>127) tmp[1]='.';
  tmp[2] = '\0';
  fputs(tmp, stdout);
}

void put2hex(u_int16 a) {
  char tmp[8];
  tmp[0] = hex[(a>>12)&15];
  tmp[1] = hex[(a>>8)&15];
  tmp[2] = ' ';
  tmp[3] = hex[(a>>4)&15];
  tmp[4] = hex[(a>>0)&15];
  tmp[5] = ' ';
  tmp[6] = '\0';
  fputs(tmp, stdout);
}



extern struct FsPhysical *ph;
extern struct FsMapper *map;
extern __y u_int16 mallocAreaY[]; /* for ramdisk */
extern u_int16 mallocAreaX[];     /* for ramboot */
void SpiLoad(register __i2 short startAddr, register __i0 short m24);

#define SPI_EEPROM_COMMAND_WRITE_ENABLE  0x06
#define SPI_EEPROM_COMMAND_WRITE_DISABLE  0x04
#define SPI_EEPROM_COMMAND_READ_STATUS_REGISTER  0x05
#define SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER  0x01
#define SPI_EEPROM_COMMAND_READ  0x03
#define SPI_EEPROM_COMMAND_WRITE 0x02
#define SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS 0x30
#define SPI_EEPROM_COMMAND_ERASE_SECTOR 0xD8
#define SPI_EEPROM_COMMAND_ERASE_4K_SECTOR 0x20


//MASTER, 8BIT, FSYNC PIN IDLE=1
#define SPI_MASTER_8BIT_CSHI   PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN8 | SPI_CF_FSIDLE1

//MASTER, 8BIT, FSYNC PIN IDLE=0 (makes /CS)
#define SPI_MASTER_8BIT_CSLO   PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN8 | SPI_CF_FSIDLE0

//MASTER, 16BIT, FSYNC PIN IDLE=0 (makes /CS)
#define SPI_MASTER_16BIT_CSLO  PERIP(SPI0_CONFIG) = SPI_CF_MASTER | SPI_CF_DLEN16 | SPI_CF_FSIDLE0

void SingleCycleCommand(u_int16 cmd){
  SPI_MASTER_8BIT_CSHI; 
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(cmd);
  SPI_MASTER_8BIT_CSHI;
}


/// Wait for not_busy (status[0] = 0) and return status
u_int16 SpiWaitStatus(void) {
  u_int16 status;
  SPI_MASTER_8BIT_CSHI;
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_READ_STATUS_REGISTER);
  while ((status = SpiSendReceive(0)) & 0x01){
    // puthex(status);puts("=status");
  }
  ; //Wait until ready
  SPI_MASTER_8BIT_CSHI;
  return status;
}


u_int16 SpiReadBlock(u_int16 blockn, u_int16 *dptr) {
  SpiWaitStatus();
  
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_READ);
  SpiSendReceive(blockn>>7);            // Address[23:16] = blockn[14:7]
  SpiSendReceive((blockn<<1)&0xff);     // Address[15:8]  = blockn[6:0]0
  SpiSendReceive(0x00);                    // Address[7:0]   = 00000000
  SPI_MASTER_16BIT_CSLO;
  {
    int n;
    for (n=0; n<256; n++){
      *dptr++ = SpiSendReceive(0);
    }
  }
  SPI_MASTER_8BIT_CSHI;

  return 0;
}


u_int16 SpiVerifyBlock(u_int16 blockn, u_int16 *dptr) {
  SpiWaitStatus();
  
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_READ);
  SpiSendReceive(blockn>>7);            // Address[23:16] = blockn[14:7]
  SpiSendReceive((blockn<<1)&0xff);     // Address[15:8]  = blockn[6:0]0
  SpiSendReceive(0x00);                    // Address[7:0]   = 00000000
  SPI_MASTER_16BIT_CSLO;
  {
    int n;
    for (n=0; n<256; n++){
      if (*dptr++ != SpiSendReceive(0)) {
	SPI_MASTER_8BIT_CSHI;	
	return 1;
      }
    }
  }
  SPI_MASTER_8BIT_CSHI;
  return 0;
}


void DumpBlock (u_int16 *dptr) {
  int n;
  for (n=0; n<256; n++){
    puthex(*dptr++);
    //put2c(*dptr++);
  }
  puts("");
}



/// Write a block to EEPROM. Caution: Does not erase block
/// \param blockn number of sector to write: 0..32767 (16Mbytes)
/// \param dptr pointer to data block
u_int16 SpiWriteBlock(u_int16 blockn, u_int16 *dptr) {
  
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
  SingleCycleCommand(SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS);
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);

  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
  SpiSendReceive(0x02); //Sector Protections Off
  SPI_MASTER_8BIT_CSHI;

  SpiWaitStatus();
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_WRITE);
  SpiSendReceive(blockn>>7);            // Address[23:16] = blockn[14:7]
  SpiSendReceive((blockn<<1)&0xff);     // Address[15:8]  = blockn[6:0]0
  SpiSendReceive(0);                    // Address[7:0]   = 00000000
 
  SPI_MASTER_16BIT_CSLO;
  {
    u_int16 n;
    for (n=0; n<128; n++){
      SpiSendReceive(*dptr++);
    }
  }
  SPI_MASTER_8BIT_CSHI;

  SpiWaitStatus();
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_WRITE);
  SpiSendReceive(blockn>>7);       
  SpiSendReceive(((blockn<<1)+1)&0xff); // Address[15:8]  = blockn[6:0]1
  SpiSendReceive(0);              
  
  SPI_MASTER_16BIT_CSLO;
  {
    int n;
    for (n=128; n<256; n++){
      SpiSendReceive(*dptr++);
    }
  }
  SPI_MASTER_8BIT_CSHI;
  SpiWaitStatus();

  return 0;
}


/// Erase one erasable block
/// Erase size for intel flash: 64K (128 disk sectors)
void SpiEraseBlock(u_int16 blockn_inside_sector){
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);  
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
  SpiSendReceive(0x02); //Sector Protections Off
  SPI_MASTER_8BIT_CSHI;
  SpiWaitStatus();
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);  
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_ERASE_SECTOR);
  SpiSendReceive(blockn_inside_sector>>7);       
  SpiSendReceive((blockn_inside_sector<<1)&0xff);
  SpiSendReceive(0);              
  SPI_MASTER_8BIT_CSHI;
  SpiWaitStatus();
}

void EraseAll(){
  register u_int16 i;
  u_int16 sn;
  puts("Blank Checking and erasing as needed up to 128KiB");
  for (sn = 0; sn<511; sn++){ //from 0 up to 16M
    SpiReadBlock(sn, minifatBuffer);
    i=0;   
    while (i<256) {
      if (minifatBuffer[i]!=0xffff){
	puthex(sn);
	SpiEraseBlock(sn);
	puts("erased");
	i=256;
      }
      i++;
    }
  }
}    



void ReadAll(){
  register u_int16 i;
  u_int16 sec,off;
  for (sec=0; sec<32768; sec++){ //from 0 up to 16M
    SpiReadBlock(sec,minifatBuffer);
    for (off=0; off<256; off+=8){
      puthex(sec*512+off*2);
      for (i=0; i<8; i++){
	put2hex (minifatBuffer[off+i]);
      }
      for (i=0; i<8; i++){
	put2c (minifatBuffer[off+i]);
      }
      fputs("\n",stdout);
      if (ReadGPIO()&0x01) return;
    }   
  }
}


#define INPUT_NAME "spiall.spi"
//#define INPUT_NAME "eeprom.img"

void Prom_vs1000img(){

  FILE *fp;
  puts("Programming " INPUT_NAME ". This does not erase old image.");

  //Detach vs3emu debugger interface interrupt for binary xfer...
  PERIP(INT_ENABLEL) &= ~INTF_RX;

  if (fp = fopen (INPUT_NAME, "rb")){
    u_int16 len;
    u_int16 sectorNumber;
    
    sectorNumber = 0;

    while ((len=fread(minifatBuffer,1,256,fp))){
      SpiWriteBlock(sectorNumber, minifatBuffer);

      if (SpiVerifyBlock(sectorNumber, minifatBuffer)){
	puts("Verify Error. You may need to erase chip.");
	PERIP(INT_ENABLEL) |= INTF_RX;
	return;
      }

      sectorNumber++;
      puthex(sectorNumber);
      //puts("=sect");
    }
    fclose(fp);       
  }else{
    puts("File not found\n");
  }

  //Reattach vs3emu debugger interface interrupt
  PERIP(INT_ENABLEL) |= INTF_RX;
  puts("Done.");
}
    

void EeUnprotect(){
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
  SPI_MASTER_8BIT_CSLO;
  SpiSendReceive(SPI_EEPROM_COMMAND_WRITE_STATUS_REGISTER);
  SpiSendReceive(0x02); //Sector Protections Off
  SPI_MASTER_8BIT_CSHI;
  SpiWaitStatus();
  SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
}

void Erase4kBlock(u_int16 blockn) {
    // Erase 4K sector
    SingleCycleCommand(SPI_EEPROM_COMMAND_WRITE_ENABLE);
    SingleCycleCommand(SPI_EEPROM_COMMAND_CLEAR_ERROR_FLAGS);
    EeUnprotect();
    SPI_MASTER_8BIT_CSLO;
    SpiSendReceive(SPI_EEPROM_COMMAND_ERASE_4K_SECTOR);
    SpiSendReceive(blockn>>7);            // Address[23:16] = blockn[14:7]
    SpiSendReceive((blockn<<1)&0xff);     // Address[15:8]  = blockn[6:0]0
    SpiSendReceive(0);                    // Address[7:0]   = 00000000
    SPI_MASTER_8BIT_CSHI;
    SpiWaitStatus();
}

void main(void) {
  char s[5];
  u_int16 i,j;

  // init spi
  SPI_MASTER_8BIT_CSHI;
  PERIP(SPI0_FSYNC) = 0; 
  PERIP(SPI0_CLKCONFIG) = SPI_CC_CLKDIV * (2-1); //clock divider 2

  PERIP(GPIO1_MODE) |= 0x1f; /* enable SPI pins */
  
  /* Make sure there is enough voltage to program the SPI memory. */
  if (voltages[voltIoPlayer] < 18) {
      voltages[voltIoPlayer]    = 18; /*2.7*/
      PowerSetVoltages(&voltages[voltCorePlayer]);
  }

  puts("\nVS1000 SPI EEPROM Write Utility");
  puts("Supports EEPROMS with 24bit address (128 kilobytes to 16 megabytes)\n");

#if 0
  SpiReadBlock(0, minifatBuffer);
  DumpBlock(minifatBuffer);
#endif

#if 1
  {
      int i = 0;
      puts("Erasing");
      while (i<RESERVED_BLOCKS) {
	  /* Only erase the firmware space */
	  puthex(i);
	  puts("");
	  Erase4kBlock(i);
	  i += 4;
      }
  }
#else
  EraseAll();
#endif
  Prom_vs1000img();
  SpiLoad(4,1);

#if 0

  while(1){
    

    puts("Reading First Sector... Data:");
    SpiReadBlock(0,minifatBuffer);
    puthex(0);
    for (i=0; i<8; i++){
      put2hex (minifatBuffer[i]);
    }
    for (i=0; i<8; i++){
      put2c (minifatBuffer[i]);
    }
    fputs("\n",stdout);
    memset(minifatBuffer, -1/*0xffffU*/, 256);


    puts("\n1) Erase all blocks\n2) Read (button 1 stops)\n3) Write EEPROM.IMG");
    fgets(s,5,stdin);


    switch(s[0]) {
    case '1':
      EraseAll();
      break;
    case '2':
      ReadAll();
      break;
    case '3':
      Prom_vs1000img();
      break;

    }
  }
#endif
}


User avatar
pasi
VLSI Staff
Posts: 2122
Joined: Thu 2010-07-15 16:04

Re: VS1000/VSMD001 bootloader

Post by pasi »

A little bit more details:

When you create the boot image with coff2allboot (see the post-build step of the vs1000 audio module solution), you can add direct memory writes using the -d option. (The writes are performed when the section is loaded.)

For GPIO0_10 (GPIO0_CS1) you need three writes: to GPIO0_MODE, GPIO0_DDR and GPIO0_ODATA (or GPIO0_SET_MASK).

For usbmass project:
coff2allboot -i vs1000spi -x 0x50 -d x:0xc010=0x0bff,0xc040=0x0400,0xc046=0x0400 $(BUILDPATH)\$(TARGET) usbmass.spi
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
Oni
User
Posts: 5
Joined: Thu 2016-10-13 15:58

Re: VS1000/VSMD001 bootloader

Post by Oni »

Thanks a lot! I will try all this today.
Oni
User
Posts: 5
Joined: Thu 2016-10-13 15:58

Re: VS1000/VSMD001 bootloader

Post by Oni »

Hi again,
I think that (thanks to you of course) I have made great progress!

My circuit seems to boot (without the watchdog) stable now, but I have to test it for some days because the error was not deterministic.
What I did:
First I tried your solution:

Code: Select all

 coff2allboot -i vs1000spi -x 0x50 -d x:0xc010=0x0bff,0xc040=0x0400,0xc046=0x0400 $(BUILDPATH)\$(TARGET) usbmass.spi 
but after applying it the boot was loading the flash software from spi forever (it was hanging).

Btw my postprocessing command before I adapted it to your solution was:

Code: Select all

 coff2spiboot -x 0x50 $(BUILDPATH)\$(TARGET) eeprom.img 
but coff2spiboot does not support memory writes, so I changed it to:

Code: Select all

coff2allboot -i vs1000spi -x 0x50 $(BUILDPATH)\$(TARGET) myplayer.spi
combineimg -o spiall.spi -m 32768 +0 myplayer.spi
copy spiall.spi eeprom.img
and then added the memory write parameter - but I got the error described before.
Then I tried something different - I made all the GPIO0_x as Inputs (which I assume let them be in a high Z state at the pin itself) and now it seems to work, code:

Code: Select all

coff2allboot -i vs1000spi -x 0x50 -d x:0xc010=0x0b00,0xc040=0x0 $(BUILDPATH)\$(TARGET) myplayer.spi
combineimg -o spiall.spi -m 32768 +0 myplayer.spi
copy spiall.spi eeprom.img
I will check the prommer code tomorrow - thanks a lot for it!
Post Reply