Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Message

Re: Fuse detection

2004-06-10 by Bruce Parham

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);
}

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.