clock speed detection when programming sam7s

Just wanted to point out a potential problem when using the sam7s flash programming capability.

I’m using reset_halt in my configuration file. I connect to my target, issue a reset, and then do a flash info. Since the main oscillator has not been enabled, the MAINRDY bit is not yet set, so the clock speed info is not valid. However, cidr in the at91sam7_info structure does get set. Any subsequent attempts to read the part info are blocked by code that tests for a non-zero cidr. This makes it necessary to kill the openocd server and restart it, then allow the processor to run until the clock is configured. At this point the flash commands should operate as expected. I’m not sure what the proper solution is in the case of an erased part. It looks like writing a 0 to FMCN may be okay in this case since the clock period should be greater than 30 us, but I’m not sure.

Also, if I’m interpreting the datasheet correctly, FMCN should be set based on the Master Clock frequency, not the Main Oscillator frequency. I think we need to take the PLL configuration into account.

Comments?

Galen

Hello

Good observations :slight_smile:

It should be possible to reread the timing info, perhaps when issuing a

flash info command. ( Simple to fix )

The code should check if the Master clock uses PLL and compute the actual

Master Clock frequency to use for FMCN. ( A bit more complicated )

The present code should be OK when using a slow clock or the Main Clock.

/Magnus

I’ve got a simple patch that changes the code such that at91sam7_read_part_info always gets called. Should I add it to the openocd patches at berlios, or would you prefer that I email it to you?

Do you want to write the clock speed detection code? I was going to do it, but I will wait if you prefer to do it yourself.

Galen

I can do it, I am already working on the GPNVM bits so there will be a patch coming “real soon now” anyway. But you can put it at the berlios patch or just in this forum.

The Main Clock frequency is estimated from MAINF. Do you think it is necessary to

be able to set the precise crystal frequency ? This means some changes must be done

to the configuration command. I think it is nice that we dont have to set it manually.

/Magnus

I put the patch on the openocd patch manager.

https://developer.berlios.de/patch/inde … up_id=4148

My patch is very simple. It is likely that you have a better idea of how to fix this.

I don’t think we need to enter the clock frequency manually. I think using MAINF will be close enough. I suspect that’s what the SAM-BA bootloader does. I’m working on the clock frequency stuff now.

Galen

This is what my present code, with clock calculatins in a separate function looks like,

UNTESTED .

#define CKGR_PLLR 0xFFFFFC2C
#define PMC_MCKR  0xFFFFFC30

#define RCFREQ 32
/** Read clock configuration and set at91sam7_info->usec_clocks*/ 
void at91sam7_read_clock_info(flash_bank_t *bank)
{
	at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
	target_t *target = at91sam7_info->target;
	unsigned long mckr, mcfr, pllr, masterfreq, mainfreq, status;
	unsigned int css, pres, mul, div;

	/* Read main clock freqency register */
	target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr);
	/* Read master clock register */
	target->type->read_memory(target, PMC_MCKR, 4, 1, (u8 *)&mckr);
	/* Read Clock Generator PLL Register  */
	target->type->read_memory(target, CKGR_PLLR, 4, 1, (u8 *)&pllr);

	pres = (mckr>>2)&0x7;
	mul = (pllr>>16)&0x7FF;
	div = pllr&0xFF;

	if (mcfr&0x10000)
	{
		css = mckr&0x03;
		at91sam7_info->mainrdy = 1;
		at91sam7_info->mainf = mcfr&0xFFFF;
		mainfreq = at91sam7_info->mainf*RCFREQ/16; /* Main Clock frequency in KHz */
		switch (css)
		{
			case 2:		/* Reserved */
			case 0:		/* Slow clock */
				masterfreq = RCFREQ;
				break;
			case 1:		/* Main Clock */
				masterfreq = mainfreq;
				break;
			case 3:		/* PLL Clock */
				/* Compute PLL Clock frequency here */
				if (div>0) 
				{
					masterfreq = (1+mul)*(mainfreq/div);
				}
				else
				{
					masterfreq = 0;
				} 
				break;
		}
		masterfreq = masterfreq>>pres;	
		at91sam7_info->usec_clocks = masterfreq/1000;	
	}
	else 
	{
		at91sam7_info->mainrdy = 0;
		at91sam7_info->mainf = 0;
		at91sam7_info->usec_clocks = 0;
	}
}

Here is my implementation of the master clock calculation.

https://developer.berlios.de/patch/inde … up_id=4148

I have briefly tested it on my atmel eval board and it appears to work, both after reset when the clock is 32 kHz, and after running when the clock is 48 MHz.

I added a master clock valid flag, but have not yet made use of it. I hope to add this tomorrow.

galen

Hello Magnus and Galen,

thank you both for working on this. Let me know when you’re both happy with the current state of the patch, and I’ll apply it to the SVN tree.

Regards,

Dominic

Hello

I have uploaded a new patch for clock handling, setting and cleraring gpnvm bits and some other minor changes.

Patch for at91sam7 flash against rev 77:

  • New command to set and clear gpnvm bits

at91sam7 gpnvm <set|clear>

This has been tested on an AT91SAM7S64

Sometimes a hard reset (power cycle ) is needed before changes are active and seen in the status.

Due to a bug in the silicon that only allows about 100 write erase cycles for this chip

(but this is not in the doc for the 7X part) I dont want do test to much on my evalboard.

  • Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):

  • The maximum number of write/erase cycles for Non Volatile Memory bits is 100. This includes

  • Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.

  • Added at91sam7_info->target_name field, makes messages more readable.

  • Setup fmcn, at91sam7_set_flash_mode(bank,2), before erasing flash.

  • Integrated work by me and galens on processor clock and timing.

some minor changes from galens last patch:

Always round up (essentially ceil() ) when calculating fmcn, this gives mninimum value of 1.

Set fmcn to 0 if at91sam7_info->mck_freq <= 33333

Call at91sam7_read_part_info(bank) when at91sam7_info->cidr == 0 and when flash info is given.

Call at91sam7_read_clock_info(bank) from at91sam7_read_part_info(bank) and before writing to flash,

( at91sam7_write, at91sam7_erase, at91sam7_protect and at91sam7_handle_gpnvm_command

Regards

Magnus