Post Go back to editing

Uniquely identify a PCB through an external ROM

Dear all,

     I need to uniquely identify a PCB that uses ADUCM3029 as micro-controller. For that i'm connecting a ROM using 1-wire protocol in a GPIO pin. I browsed the ADI drivers and examples however I didn't find anything related to this matter, so I started writing a 1-wire protocol driver to read this ROM. One of the configuration needed is a pull-up resistor connecting to this pin. I'm asking:

what is value of the internal GPIO pull-up resistors?

Did Analog Devices has already an example or documentation concerning the 1-wire protocol?

Regards,

Mohamed Amine MESSAOUD

  • Hello Messaoud,

    The datasheet specifies that at the maximum battery supply voltage of 3.6V and 0V input on the GPIO the pull-up will sink 100uA.

    http://www.analog.com/media/en/technical-documentation/data-sheets/ADuCM3027_3029.pdf

    Currently there is no 1-wire example from ADI that I could find.

    Regards,

    Andrei.

  • I tried to write a driver for this DS2401 could you review it with me. 

    This is the one_wire_driver.h header file

    #ifndef ONE_WIRE_DRIVER
    #define ONE_WIRE_DRIVER
    /*
       see
       https://www.maximintegrated.com/en/app-notes/index.mvp/id/126
    */
    #include <adi_processor.h>
    #include "ADuCM3029.H"
    #include <stddef.h>		/* for 'NULL' */
    #include <string.h>		/* for strlen */
    #include <stdint.h>
    #include <drivers/pwr/adi_pwr.h>
    #include <drivers/gpio/adi_gpio.h>
    #include <drivers/dma/adi_dma.h>
    #include "common.h"
    #include <drivers/general/adi_drivers_general.h>
    
    #define STANDARD_SPEED_A         6u
    #define STANDARD_SPEED_B         64u
    #define STANDARD_SPEED_C         60u
    #define STANDARD_SPEED_D         10u
    #define STANDARD_SPEED_E         9u
    #define STANDARD_SPEED_F         55u
    #define STANDARD_SPEED_G         0u
    #define STANDARD_SPEED_H         480u
    #define STANDARD_SPEED_I         70u
    #define STANDARD_SPEED_J         410u
    
    #define DS2401_READ_ROM_COMMAND	 0x33
    
    
    /* tick every 1us*/
    #define TICKS        (26000000u / 1000000u)
    
    volatile uint32_t usTicks = 0; 
    
    
    typedef struct{
        ADI_GPIO_PORT port;
        ADI_GPIO_DATA pins;
    } PinMap;
    
    
    void delay_us(uint32_t nus);
    
    /* 1-wire basic functions */
    uint16_t OWTouchReset(PinMap _1wd_pin);
    void OWWriteBit(uint8_t bit,PinMap _1wd_pin);
    uint16_t OWReadBit(PinMap _1wd_pin);
    
    /* 1-wire drived functions */
    void OWWriteByte(uint8_t data,PinMap _1wd_pin);
    uint8_t OWReadByte(PinMap _1wd_pin);
    uint8_t OWTouchByte(uint8_t data,PinMap _1wd_pin);
    void OWBlock(uint8_t *data, uint8_t data_len,PinMap _1wd_pin);
    #endif /* ONE_WIRE_DRIVER */
    

    And this is the implementation

    #include "one_wire_driver.h"
    
    /* delay in µs unit*/
    void delay_us(uint32_t nus) {
        while (nus--) {
          while (usTicks != 0) 
          {
          }
        }
    }
    
    /* Tick every 1µs*/
    void SysTick_Handler(){
        usTicks++;
        if(usTicks==26000000u)
        {
           usTicks=0;
        }
    }
    
    uint8_t ROM_VALUE[8];
    volatile uint8_t family_code;
    volatile uint64_t serial_number;
    volatile uint8_t crc_byte;
    
    int main(void)
    {
         PinMap data_DS2401 = { ADI_GPIO_PORT1, ADI_GPIO_PIN_13 };
        /* initialisations */
        uint8_t         gpioMemory[ADI_GPIO_MEMORY_SIZE] = {0};
        ADI_PWR_RESULT  ePwrResult;
        ADI_GPIO_RESULT eGpioResult;
        common_Init();
        
        ePwrResult = adi_pwr_Init();
        DEBUG_RESULT("adi_pwr_Init failed.", ePwrResult, ADI_PWR_SUCCESS);
        ePwrResult = adi_pwr_SetClockDivider(ADI_CLOCK_HCLK, 1u);
        DEBUG_RESULT("adi_pwr_SetClockDivider (HCLK) failed.", ePwrResult, ADI_PWR_SUCCESS);
        ePwrResult = adi_pwr_SetClockDivider(ADI_CLOCK_PCLK, 1u);
        DEBUG_RESULT("adi_pwr_SetClockDivider (PCLK) failed.", ePwrResult, ADI_PWR_SUCCESS);
        
        /* initialize the systick driver */
        SysTick_Config(TICKS);
        
        /* Initialize GPIO driver */
        eGpioResult= adi_gpio_Init(gpioMemory, ADI_GPIO_MEMORY_SIZE);
        DEBUG_RESULT("adi_GPIO_Init failed.", eGpioResult, ADI_GPIO_SUCCESS);
        
        /* set output enable */
        eGpioResult = adi_gpio_OutputEnable(data_DS2401.port, data_DS2401.pins, true);
        DEBUG_RESULT("adi_GPIO_SetOutputEnable failed on data_DS2401.", eGpioResult, ADI_GPIO_SUCCESS);
        /* set pull up. In this case pull-up resistor is external */
        //eGpioResult = adi_gpio_PullUpEnable(data_DS2401.port,data_DS2401.pins,true);
        //DEBUG_RESULT("adi_gpio_PullUpEnable failed on data_DS2401.", eGpioResult, ADI_GPIO_SUCCESS);
        eGpioResult = adi_gpio_SetHigh(data_DS2401.port, data_DS2401.pins);
        DEBUG_RESULT("adi_gpio_SetHigh data_DS2401.port.", eGpioResult, ADI_GPIO_SUCCESS);
        /* read DS2401 ROM */
        if(OWTouchReset(data_DS2401))
        {
            /* send read ROM Command */
            OWWriteByte(DS2401_READ_ROM_COMMAND,data_DS2401);
            /* read ROM_VALUE */
            OWBlock(ROM_VALUE,8,data_DS2401);
            /* parse family_code */
            family_code=ROM_VALUE[0];
            /* parse Serial_Number*/
            uint8_t loop;
            for(loop=1;loop<8;loop++)
                serial_number|=(64-8*loop)>>ROM_VALUE[loop];
            /* parse crc_byte */
            crc_byte=ROM_VALUE[8];
        }
        
    }
    
    uint16_t  OWTouchReset(PinMap _1wd_pin)
    {
        uint16_t  result;
        ADI_GPIO_RESULT eGpioResult;
        delay_us(STANDARD_SPEED_G);
        eGpioResult = adi_gpio_SetLow (_1wd_pin.port, _1wd_pin.pins);
        delay_us(STANDARD_SPEED_H);
        /*  release the bus */
        eGpioResult = adi_gpio_SetHigh(_1wd_pin.port, _1wd_pin.pins);
        delay_us(STANDARD_SPEED_I);
        /* Sample for presence pulse from slave */
        eGpioResult = adi_gpio_GetData(_1wd_pin.port,_1wd_pin.pins,&result);
        delay_us(STANDARD_SPEED_J);
        return result;
    }
    
    void OWWriteBit(uint8_t bit,PinMap _1wd_pin)
    {
        ADI_GPIO_RESULT eGpioResult;
        eGpioResult = adi_gpio_SetLow(_1wd_pin.port, _1wd_pin.pins);
        if(bit)
            {
                 /* write 1 bit */
                 delay_us(STANDARD_SPEED_A);
                 /*  release the bus */
                 eGpioResult = adi_gpio_SetHigh(_1wd_pin.port, _1wd_pin.pins);
                 delay_us(STANDARD_SPEED_B);             
            }
        else
            {
                 /* write 0 bit */
                 delay_us(STANDARD_SPEED_C);
                 /*  release the bus */
                 eGpioResult = adi_gpio_SetHigh(_1wd_pin.port, _1wd_pin.pins);
                 delay_us(STANDARD_SPEED_D);
            }
    }
    
    uint16_t OWReadBit(PinMap _1wd_pin)
    {
        uint16_t result;
        ADI_GPIO_RESULT eGpioResult;
        eGpioResult = adi_gpio_SetLow(_1wd_pin.port, _1wd_pin.pins);
        delay_us(STANDARD_SPEED_A);
        /*  release the bus */
        eGpioResult = adi_gpio_SetHigh(_1wd_pin.port, _1wd_pin.pins);
        delay_us(STANDARD_SPEED_E);
        /* Sample the bit value from slave */
        eGpioResult = adi_gpio_GetData(_1wd_pin.port,_1wd_pin.pins,&result);
        delay_us(STANDARD_SPEED_F);
        return result;
    }
    
    void OWWriteByte(uint8_t data,PinMap _1wd_pin)
    {
        uint8_t loop;
        // Loop to write each bit in the byte, LS-bit first
        for (loop = 0; loop < 8; loop++)
        {
            OWWriteBit(data & 0x01,_1wd_pin);
            // shift the data byte for the next bit
            data >>= 1;
        }
    }
    
    uint8_t OWReadByte(PinMap _1wd_pin)
    {
        uint8_t loop,result;
        for(loop = 0; loop < 8; loop++)
        {
            // shift the result to get it ready for the next bit
            result >>= 1;
            // if result is one, then set MS bit
            if(OWReadBit(_1wd_pin))
                result|= 0x80;
        }
        return result;
    }
    
    /*
     * Write a 1-Wire data byte and return the sampled result.
    */
    uint8_t OWTouchByte(uint8_t data,PinMap _1wd_pin)
    {
        uint8_t loop,result;
        for(loop = 0; loop < 8; loop++)
        {
            // shift the result to get it ready for the next bit
            result >>= 1;
            // If sending a '1' then read a bit else write a '0'
            if(data & 0x01)
            {
                if(OWReadBit(_1wd_pin))
                    result |= 0x80;
            }
            else
                OWWriteBit(0,_1wd_pin);
            // shift the data byte for the next bit
            data >>= 1;
        }
        return result;
    }
    
    void OWBlock(uint8_t *data, uint8_t data_len,PinMap _1wd_pin)
    {
        uint8_t loop;
        for(loop = 0; loop < data_len; loop++)
        {
            data[loop] = OWTouchByte(data[loop],_1wd_pin);
        }
    }
    
    

  • Hello!

    I was able to find two potential problems:

    1. Configuring SysTick to interrupt every 1us could hang the program because the interrupt would be too often for it to do much else. Try to make #define TICKS (26000000u/100000u) and adjust the STANDARD_SPEED defines accordingly considering that now the timer ticks every 10us instead of every 1us.

    2. You should enable the input driver for the GPIO pin you are using by calling adi_gpio_InputEnable.

    Regards,

    Andrei.

  • Just a point to add on Andrei's comments. While the MCU is driving the bus, Output Enable should be True and while sampling the bus, Output Enable should be False & Input Enable should be True. 

    Regards,

    Rajalakshmi

  • a 1us second interrupt is required to use this protocol according to https://www.maximintegrated.com/en/app-notes/index.mvp/id/126, some delays of the standard speed are not multiples of 10us. How these delays could be modified? 

  • I think the 1us time delay is only required for overdrive mode. I believe that it can work with 10us delay.

    This tutorial on 1-wire mentions the time intervals that can be used in 1-wire implementation.

    https://www.maximintegrated.com/en/products/1-wire/flash/overview/index.cfm

    You can change:

    STANDARD_SPEED_A  1

    STANDARD_SPEED_B  7 (or 8 if the slave is particularly slow)

    STANDARD_SPEED_E  1 (or 0 if the slave is particularly fast)

    STANDARD_SPEED_F  5 (or 6 if STANDARD_SPEED_E is 0)

    And the rest are evenly divided by 10.

    The critical part is the STANDARD_SPEED_E because in the tutorial the master needs to read at exactly 15us. If it does not work with 1 or 0 try changing #define TICKS (26000000u/200000u) and use

    STANDARD_SPEED_A  2

    STANDARD_SPEED_B 12

    STANDARD_SPEED_E  1

    and the rest are divided by 5.

    Hope this helps.

    All the best,

    Andrei

  • Thank you for your help. Feel free test the code. Once I tested It I will re-post it to be used.