It turns out that M103 mode detection on the M128 is fairly straight forward. If the
M103 fuse is programmed, the SPMCSR register is disabled and replaced by RAM. The
trick is to set the SPMEN bit and wait for more than four clocks. If it's still set
after four clocks, it's RAM and the M103C fuse must be set. Otherwise, the SPMCSR
is active and the M103C fuse is unprogrammed.
The stuff below reflects this addition.
Bruce
----------------------------------------------------------------------------------
struct M128_FUSES
{
unsigned cksel : 4; // low byte
unsigned sut : 2;
unsigned boden : 1;
unsigned bodlevel : 1;
unsigned bootrst : 1; // high byte
unsigned bootsz : 2;
unsigned eesave : 1;
unsigned ckopt : 1;
unsigned spien : 1;
unsigned jtagen : 1;
unsigned ocden : 1;
unsigned wdton : 1; // extension byte
unsigned m103c : 1;
unsigned unused : 6;
unsigned lb : 2; // lock bit byte
unsigned blb0 : 2;
unsigned blb1 : 2;
};
union FUSES
{
struct M128_FUSES f_bits;
unsigned long fuse_state;
} fuses;
unsigned long get_fuse(void) // get fuses to test clock source and stuff...
{
asm
(
"ldi r26, 9 ; BLBSET & SPMEN \n"
"mov r0, r26 ; to read fuses \n"
"ldi r26, 0x68 ; spmcsr \n"
"ldi r27, 0 \n"
"ldi r30, 0 ; start with FLB \n"
"ldi r31, 0 \n"
"ldi r18, 0 ; in case M103C is set \n"
"ld r1, x ; in case it's just ram \n"
"st x, r0 ; set the spmen bit \n"
);
asm
(
"nop ; timeout the spmen bit \n"
"nop \n"
"nop \n"
"nop \n"
"nop \n"
"nop \n"
"ld r16, x ; spmcsr or ram \n"
"sbrs r16, 0 ; skip if spmen still set \n"
"rjmp get_fuse1 ; M103C fuse not set! \n"
"st x, r1 ; replace ram value... \n"
"rjmp get_fusex ; bomb out w/R18 zero \n"
);
asm
(
"get_fuse1: \n"
"st x, r0 ; prime the pump \n"
"lpm r16, z+ ; fuse low byte -> R16 \n"
"st x, r0 \n"
"lpm r19, z+ ; lock byte -> R19 \n"
"st x, r0 \n"
"lpm r18, z+ ; fuse ext byte -> R18 \n"
"st x, r0 \n"
"lpm r17, z ; fuse high byte -> R17 \n"
);
asm
(
"get_fusex: \n"
"adiw r28, 4 ; r20-r23 was pushed \n"
"ret \n"
);
return(0); // keep the compiler from whinning
}
// Display M128 fuses @ startup.
// Returns TRUE if in M128 mode, FALSE if M103 mode
int show_fuses(void)
{
fuses.fuse_state = get_fuse();
if(fuses.f_bits.m103c == 0) // ack! 103 emulation...
{
printf("\033[2J\nProcessor is in M103 Mode, Fuse access denied!");
return(0);
}
printf("\nProcessor Fuses:\n\n");
printf(" cksel = %1u sut = %1u boden = %1u bodlevel = %1u\n",
fuses.f_bits.cksel, fuses.f_bits.sut, fuses.f_bits.boden, fuses.f_bits.bodlevel);
printf("bootrst = %1u bootsz = %1u eesave = %1u ckopt = %1u\n",
fuses.f_bits.bootrst, fuses.f_bits.bootsz, fuses.f_bits.eesave, fuses.f_bits.ckopt);
printf(" spien = %1u jtagen = %1u ocden = %1u wdten = %1u\n",
fuses.f_bits.spien, fuses.f_bits.jtagen, fuses.f_bits.ocden, fuses.f_bits.wdton);
printf(" M103c = %1u lb = %1u blb0 = %1u blb1 = %1u\n",
fuses.f_bits.m103c, fuses.f_bits.lb, fuses.f_bits.blb0, fuses.f_bits.blb1);
return(-1);
}Message
Re: Fuse detection
2004-06-10 by Bruce Parham
Attachments
- No local attachments were found for this message.