Onewire pro LPC1114

Jaroslav Buchta jaroslav.buchta na hascomp.cz
Pondělí Leden 27 19:45:38 CET 2014


Ja to implementoval na STM32, klicove je casovani tech kratkych 
intervalu desitek us, ja to delal prostrednictvim casovace. Samozrejme 
je problem vyuzivat nejaka preruseni behem techto kritickych useku, pro 
UART pouzivam DMA, FreeRTOS ma blokovana preruseni.
Pro inspiraci zdrojak (neni jeste nejak ucesany):


///////////////////////////////////////////////////////////////////////////////
#include "main.h"
#include <string.h>
#include "DS1820.h"


///////////////////////////////////////////////////////////////////////////////

#define OW_ONE_BUS
#define OW_OPENCOLL

#define DS_PERIPHIO RCC_APB2Periph_GPIOB
#define DS_PORT     GPIOB
#define DS_PIN_I1    GPIO_Pin_6
#define DS_PIN_O1    GPIO_Pin_7
#define DS_PIN_I2    GPIO_Pin_8
#define DS_PIN_O2    GPIO_Pin_9
#define DS_PERIPHTM RCC_APB1Periph_TIM2
#define DS_TIMER    TIM2




///////////////////////////////////////////////////////////////////////////////

#define CRC8INIT    0x00
#define CRC8POLY    0x18              //0X18 = X^8+X^5+X^4+X^0

uint8_t    crc8 ( uint8_t *data_in, uint8_t number_of_bytes_to_read )
{
     uint8_t    crc;
     uint8_t     loop_count;
     uint8_t      bit_counter;
     uint8_t      data;
     uint8_t      feedback_bit;

     crc = CRC8INIT;

     for (loop_count = 0; loop_count != number_of_bytes_to_read; 
loop_count++)
     {
         data = data_in[loop_count];
         bit_counter = 8;
         do
         {
             feedback_bit = (crc ^ data) & 0x01;

             if ( feedback_bit == 0x01 )
             {
                 crc = crc ^ CRC8POLY;
             }
             crc = (crc >> 1) & 0x7F;
             if ( feedback_bit == 0x01 )
             {
                 crc = crc | 0x80;
             }

             data = data >> 1;
             bit_counter--;

         }
         while (bit_counter > 0);
     }

     return crc;
}


///////////////////////////////////////////////////////////////////////////////

void ow_Init()
{
     // Init port pins
     RCC_APB2PeriphClockCmd(DS_PERIPHIO, ENABLE);
     GPIO_SetBits(DS_PORT, DS_PIN_O1 | DS_PIN_O2);
     GPIO_InitTypeDef iodef_i = {DS_PIN_I1 | DS_PIN_I2, 
GPIO_Speed_10MHz, GPIO_Mode_IPU};
     GPIO_Init(DS_PORT, &iodef_i);
     GPIO_InitTypeDef iodef_o = {DS_PIN_O1 | DS_PIN_O2, 
GPIO_Speed_10MHz, GPIO_Mode_Out_PP};
     GPIO_Init(DS_PORT, &iodef_o);

     // Init timer
     /* Compute the prescaler value */
     uint16_t PrescalerValue = (uint16_t) (SystemCoreClock / 1000000UL) - 1;

     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
     /* Time base configuration */
     RCC_APB1PeriphClockCmd(DS_PERIPHTM, ENABLE);
     TIM_TimeBaseStructure.TIM_Period = 65535;
     TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
     TIM_TimeBaseStructure.TIM_ClockDivision = 0;
     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
     TIM_TimeBaseInit(DS_TIMER, &TIM_TimeBaseStructure);
     TIM_Cmd(DS_TIMER, ENABLE);
}


static void __INLINE DelayUs(uint16_t us)
{
     uint16_t cnts = DS_TIMER->CNT;
     while ((uint16_t)(DS_TIMER->CNT - cnts) < us);
}

/*******************************************/

#define OW_MATCH_ROM    0x55
#define OW_SKIP_ROM        0xCC
#define    OW_SEARCH_ROM    0xF0





uint8_t ow_reset(uint8_t devId)
{
     uint16_t err;
     uint16_t pinO = devId == 0 ? DS_PIN_O1 : DS_PIN_O2;
     uint16_t pinI = devId == 0 ? DS_PIN_I1 : DS_PIN_I2;

     DS_PORT->BRR = pinO;
     DelayUs(500);
     DS_PORT->BSRR = pinO;
     __disable_irq();
     DelayUs(66);
     err = DS_PORT->IDR & pinI;            // no presence detect
     __enable_irq();
     DelayUs(480-66);
     if( (DS_PORT->IDR & pinI) == 0 )    // short circuit
         err = 1;

     return err;
}

/* Timing issue when using runtime-bus-selection (!OW_ONE_BUS):
    The master should sample at the end of the 15-slot after initiating
    the read-time-slot. The variable bus-settings need more
    cycles than the constant ones so the delays had to be shortened
    to achive a 15uS overall delay
    Setting/clearing a bit in I/O Register needs 1 cyle in OW_ONE_BUS
    but around 14 cyles in configureable bus (us-Delay is 4 cyles per uS) */
uint8_t ow_bit_io( uint8_t b, uint8_t devId)
{
        uint16_t pinO = devId == 0 ? DS_PIN_O1 : DS_PIN_O2;
     uint16_t pinI = devId == 0 ? DS_PIN_I1 : DS_PIN_I2;
     __disable_irq();
     DS_PORT->BRR = pinO;
     DelayUs(2); // Recovery-Time wuffwuff was 1
     if ( b )
     {
         DS_PORT->BSRR = pinO;
     }
     // wuffwuff delay was 15uS-1 see comment above
     DelayUs(15-2);
     if((DS_PORT->IDR & pinI) == 0) b = 0;  // sample at end of 
read-timeslot
     DelayUs(60-15-2);
     DS_PORT->BSRR = pinO;
     __enable_irq();
     DelayUs(15);
     return b;
}


uint8_t ow_byte_wr( uint8_t b, uint8_t devId)
{
     uint8_t i = 8, j;

     do {
         j = ow_bit_io( b & 1, devId);
         b >>= 1;
         if( j ) b |= 0x80;
     } while( --i );

     return b;
}


uint8_t ow_byte_rd(uint8_t devId)
{
   // read by sending 0xff (a dontcare?)
   return ow_byte_wr(0xFF, devId);
}


uint8_t ow_rom_search( uint8_t diff, uint8_t* id, uint8_t devId)
{
     uint8_t i, j, next_diff;
     uint8_t b;

DS_PORT->BRR = DS_PIN_O2;
     if( ow_reset(devId) ) return OW_PRESENCE_ERR;    // error, no 
device found
DS_PORT->BSRR = DS_PIN_O2;

     ow_byte_wr( OW_SEARCH_ROM, devId );            // ROM search command
     next_diff = OW_LAST_DEVICE;            // unchanged on last device

     i = OW_ROMCODE_SIZE * 8;                    // 8 bytes

     do
     {
         j = 8;                    // 8 bits
         do
         {
             b = ow_bit_io( 1, devId );            // read bit
             if( ow_bit_io( 1, devId ) )
             {                            // read complement bit
                 if( b )                    // 11
                 return OW_DATA_ERR;            // data error
             }
             else
             {
                 if( !b ) {                // 00 = 2 devices
                     if( diff > i || ((*id & 1) && diff != i) )
                     {
                         b = 1;                // now 1
                         next_diff = i;        // next pass 0
                     }
                 }
             }
             ow_bit_io( b, devId );                 // write bit
             *id >>= 1;
             if( b ) *id |= 0x80;            // store bit

             i--;

         } while( --j );

         id++;                    // next uint8_t

     } while( i );

     return next_diff;                // to continue search
}


void ow_command( uint8_t command, uint8_t *id, uint8_t devId)
{
     uint8_t i;

     ow_reset(devId);

     if( id )
     {
         ow_byte_wr( OW_MATCH_ROM, devId);            // to a single device
         i = OW_ROMCODE_SIZE;
         do
         {
             ow_byte_wr( *id, devId);
             id++;
         } while( --i );
     }
     else
     {
         ow_byte_wr( OW_SKIP_ROM, devId);            // to all devices
     }

     ow_byte_wr( command, devId);
}



/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

/* return values */
#define DS18X20_OK          0x00
#define DS18X20_ERROR       0x01
#define DS18X20_START_FAIL  0x02
#define DS18X20_ERROR_CRC   0x03

#define DS18X20_POWER_PARASITE 0x00
#define DS18X20_POWER_EXTERN   0x01

/* DS18X20 specific values (see datasheet) */
#define DS18S20_ID 0x10
#define DS18B20_ID 0x28

#define DS18X20_CONVERT_T    0x44
#define DS18X20_READ        0xBE
#define DS18X20_WRITE        0x4E
#define DS18X20_EE_WRITE    0x48
#define DS18X20_EE_RECALL    0xB8
#define DS18X20_READ_POWER_SUPPLY 0xB4

#define DS18B20_CONF_REG    4
#define DS18B20_9_BIT       0
#define DS18B20_10_BIT      (1<<5)
#define DS18B20_11_BIT      (1<<6)
#define DS18B20_12_BIT      ((1<<6)|(1<<5))

// indefined bits in LSB if 18B20 != 12bit
#define DS18B20_9_BIT_UNDF ((1<<0)|(1<<1)|(1<<2))
#define DS18B20_10_BIT_UNDF      ((1<<0)|(1<<1))
#define DS18B20_11_BIT_UNDF      ((1<<0))
#define DS18B20_12_BIT_UNDF      0

// conversion times in ms
#define DS18B20_TCONV_12BIT      750
#define DS18B20_TCONV_11BIT      DS18B20_TCONV_12BIT/2
#define DS18B20_TCONV_10BIT      DS18B20_TCONV_12BIT/4
#define DS18B20_TCONV_9BIT       DS18B20_TCONV_12BIT/8
#define DS18S20_TCONV            DS18B20_TCONV_12BIT

// constant to convert the fraction bits to cel*(10^-4)
#define DS18X20_FRACCONV         625

#define DS18X20_SP_SIZE  9

// DS18X20 EEPROM-Support
#define DS18X20_WRITE_SCRATCHPAD  0x4E
#define DS18X20_COPY_SCRATCHPAD   0x48
#define DS18X20_RECALL_E2         0xB8
#define DS18X20_COPYSP_DELAY      10 /* ms */
#define DS18X20_TH_REG      2
#define DS18X20_TL_REG      3



///////////////////////////////////////////////////////////////////////////////

/* find DS18X20 Sensors on 1-Wire-Bus
    input/ouput: diff is the result of the last rom-search
    output: id is the rom-code of the sensor found */
void DS18X20_find_sensor(uint8_t *diff, uint8_t *id, uint8_t devId)
{
     for (;;)
     {
         *diff = ow_rom_search( *diff, &id[0], devId);
         if ( *diff==OW_PRESENCE_ERR || *diff==OW_DATA_ERR ||
           *diff == OW_LAST_DEVICE ) return;
         if ( id[0] == DS18B20_ID || id[0] == DS18S20_ID ) return;
     }
}

/* get power status of DS18x20
    input  : id = rom_code
    returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE */
uint8_t    DS18X20_get_power_status(uint8_t *id, uint8_t devId)
{
     uint8_t pstat;
     ow_reset(devId);
     ow_command(DS18X20_READ_POWER_SUPPLY, id, devId);
     pstat=ow_bit_io(1, devId); // pstat 0=is parasite/ !=0 ext. powered
     ow_reset(devId);
     return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
}

/* start measurement (CONVERT_T) for all sensors if input id==NULL
    or for single sensor. then id is the rom-code */
uint8_t DS18X20_start_meas(uint8_t *id, uint8_t devId)
{
     if (ow_reset(devId))
         return DS18X20_ERROR; //**
     ow_command( DS18X20_CONVERT_T, id, devId);
     return DS18X20_OK;
}

/* reads temperature (scratchpad) of sensor with rom-code id
    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
    in millicelsius*0.1
    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000°C */
uint8_t DS18X20_read_meas(uint8_t *id, uint16_t *tempRaw, uint8_t devId)
{
     uint8_t i;
     uint8_t sp[DS18X20_SP_SIZE];
     uint16_t meas;

     if (ow_reset(devId))
         return DS18X20_ERROR; //**
     ow_command(DS18X20_READ, id, devId);
     for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) sp[i]=ow_byte_rd(devId);
     if ( crc8( &sp[0], DS18X20_SP_SIZE ) )
         return DS18X20_ERROR_CRC;

     meas = sp[0];  // LSB
     meas |= ((uint16_t)sp[1])<<8; // MSB
     //meas = 0xff5e; meas = 0xfe6f;

     //  only work on 12bit-base
     if( id[0] == DS18S20_ID )
     { // 9 -> 12 bit if 18S20
         /* Extended measurements for DS18S20 contributed by Carsten Foss */
         meas &= (uint16_t) 0xfffe;    // Discard LSB , needed for later 
extended precicion calc
         meas <<= 3;                    // Convert to 12-bit , now 
degrees are in 1/16 degrees units
//        meas += (16 - sp[6]) - 4;    // Add the compensation , and 
remember to subtract 0.25 degree (4/16)
         meas += 16*((uint16_t)sp[7] - (uint16_t)sp[6])/(uint16_t)sp[7] 
- 4;    // Add the compensation , and remember to subtract 0.25 degree 
(4/16)
     }
     else
     {
         meas = 0;        // unsupported now
     }

     *tempRaw = meas;
     return DS18X20_OK;
}

/*
#ifdef DS18X20_EEPROMSUPPORT

uint8_t DS18X20_write_scratchpad( uint8_t id[],
     uint8_t th, uint8_t tl, uint8_t conf)
{
     ow_reset(); //
     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
         ow_command( DS18X20_WRITE_SCRATCHPAD, id );
         ow_byte_wr(th);
         ow_byte_wr(tl);
         if (id[0] == DS18B20_ID) ow_byte_wr(conf); // config avail. on 
B20 only
         return DS18X20_OK;
     }
     else {
         #ifdef DS18X20_VERBOSE
         uart_puts_P( "DS18X20_write_scratchpad: Short Circuit !\r\n" );
         #endif
         return DS18X20_ERROR;
     }
}

uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[] )
{
     uint8_t i;

     ow_reset(); //
     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
         ow_command( DS18X20_READ, id );
         for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) sp[i]=ow_byte_rd();
         return DS18X20_OK;
     }
     else {
         #ifdef DS18X20_VERBOSE
         uart_puts_P( "DS18X20_read_scratchpad: Short Circuit !\r\n" );
         #endif
         return DS18X20_ERROR;
     }
}

uint8_t DS18X20_copy_scratchpad( uint8_t with_power_extern,
     uint8_t id[] )
{
     ow_reset(); //
     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
         ow_command( DS18X20_COPY_SCRATCHPAD, id );
         if (with_power_extern != DS18X20_POWER_EXTERN)
             ow_parasite_enable();
         delay_ms(DS18X20_COPYSP_DELAY); // wait for 10 ms
         if (with_power_extern != DS18X20_POWER_EXTERN)
             ow_parasite_disable();
         return DS18X20_OK;
     }
     else {
         #ifdef DS18X20_VERBOSE
         uart_puts_P( "DS18X20_copy_scratchpad: Short Circuit !\r\n" );
         #endif
         return DS18X20_START_FAIL;
     }
}

uint8_t DS18X20_recall_E2( uint8_t id[] )
{
     ow_reset(); //
     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
         ow_command( DS18X20_RECALL_E2, id );
         // TODO: wait until status is "1" (then eeprom values
         // have been copied). here simple delay to avoid timeout
         // handling
         delay_ms(DS18X20_COPYSP_DELAY);
         return DS18X20_OK;
     }
     else {
         #ifdef DS18X20_VERBOSE
         uart_puts_P( "DS18X20_recall_E2: Short Circuit !\r\n" );
         #endif
         return DS18X20_ERROR;
     }
}
#endif
*/


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
DS18X20_DESC    DsTSensDesc1[OW_MAX_DEVICES];
DS18X20_DESC    DsTSensDesc2[OW_MAX_DEVICES];
uint8_t            DsTSensCount1;
uint8_t            DsTSensCount2;


///////////////////////////////////////////////////////////////////////////////

void TSens_Init()
{
     ow_Init();
     memset(DsTSensDesc1, 0x00, sizeof(DsTSensDesc1));
     memset(DsTSensDesc2, 0x00, sizeof(DsTSensDesc2));
     DsTSensCount1 = 0;
     DsTSensCount2 = 0;
}

///////////////////////////////////////////////////////////////////////////////

uint8_t TSens_ScanForDevices(uint8_t devId)
{
     uint8_t b;
     uint8_t id[OW_ROMCODE_SIZE];

     b = ow_reset(devId);
     if (b) return TSENS_ERR_HW;

     b = OW_SEARCH_FIRST;

     if (devId== 0)
     {
         DsTSensCount1 = 0;
         memset(DsTSensDesc1, 0x00, sizeof(DsTSensDesc1));

         while (DsTSensCount1 < OW_MAX_DEVICES)
         {
             DS18X20_find_sensor(&b, id, devId);
             if (b == OW_PRESENCE_ERR) return TSENS_ERR_HW;
             if (b == OW_DATA_ERR) return TSENS_ERR_DATA;

             PDS18X20_DESC pd = &DsTSensDesc1[DsTSensCount1++];
             memcpy(pd->id, id, OW_ROMCODE_SIZE);
             pd->status = TSENS_ERR_VOID;
             if (b == OW_LAST_DEVICE) break;
         }
     }
     else
     {
         DsTSensCount2 = 0;
         memset(DsTSensDesc2, 0x00, sizeof(DsTSensDesc2));

         while (DsTSensCount2 < OW_MAX_DEVICES)
         {
             DS18X20_find_sensor(&b, id, devId);
             if (b == OW_PRESENCE_ERR) return TSENS_ERR_HW;
             if (b == OW_DATA_ERR) return TSENS_ERR_DATA;

             PDS18X20_DESC pd = &DsTSensDesc2[DsTSensCount2++];
             memcpy(pd->id, id, OW_ROMCODE_SIZE);
             pd->status = TSENS_ERR_VOID;
             if (b == OW_LAST_DEVICE) break;
         }
     }
     return TSENS_ERR_OK;
}

///////////////////////////////////////////////////////////////////////////////

uint8_t *TSens_GetCntPtr(uint8_t devId)
{
     if (devId== 0)     return &DsTSensCount1;
     return &DsTSensCount2;
}

///////////////////////////////////////////////////////////////////////////////
PDS18X20_DESC TSens_GetConfPtr(uint8_t idx, uint8_t devId)
{
     if (devId == 0) return DsTSensDesc1+idx;
     return DsTSensDesc2+idx;
}
///////////////////////////////////////////////////////////////////////////////

static int8_t  nDevIdx = -2;
static uint32_t wStartTicks = 0;

int TSens_SrvFunc (uint8_t devId)
{
     uint8_t bRes = DS18X20_OK;
     PDS18X20_DESC pd = DsTSensDesc1;
     uint8_t cnt = DsTSensCount1;
     if (devId != 0)
     {
         pd = DsTSensDesc2;
         cnt = DsTSensCount2;
     }
     if (nDevIdx == -2)
     {
         bRes = DS18X20_start_meas(NULL, devId);
         wStartTicks = GetTickCount();
         if (bRes != DS18X20_OK)
         {
             uint8_t idx;

             for (idx=0; idx<cnt; idx++)
             {
                 pd++->status = TSENS_ERR_HW;
             }
         }
         else
         {
             nDevIdx = -1;
         }
     }
     else if (nDevIdx == -1)
     {
         if (GetTickCount() - wStartTicks > DS18S20_TCONV) nDevIdx = 0;
     }
     else if (nDevIdx < cnt)
     {
         bRes = DS18X20_read_meas(pd->id, &pd->tempRaw, devId);
         if (bRes == DS18X20_OK)
         {
             pd->status = TSENS_ERR_OK;
         }
         else
         {
             pd->status = TSENS_ERR_HW;
         }
         nDevIdx++;
     }
     else
     {
         nDevIdx = -2;
     }
     return bRes == DS18X20_OK ? 1 : 0;
}


///////////////////////////////////////////////////////////////////////////////




Dne 27.1.2014 19:39, Marek Sembol napsal(a):
> Nemate nekdo odzkousenou implementaci 1-wire pro LPC1xxx?
> Marek
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list



---
Tato zpráva neobsahuje viry ani jiný škodlivý kód - avast! Antivirus je aktivní.
http://www.avast.com
------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20140127/e6b88bf8/attachment-0001.html>


Další informace o konferenci Hw-list