Onewire pro LPC1114
Marek Sembol
hwm.land na gmail.com
Pondělí Leden 27 20:12:06 CET 2014
Dekuji, to mi bude rozhodne stacit. V podstate klicove je
static void __INLINE DelayUs(uint16_t us)
{
uint16_t cnts = DS_TIMER->CNT;
while ((uint16_t)(DS_TIMER->CNT - cnts) < us);
}
Nedoslo mi jak jednoduse ty us cekacky udelat. Mrknu rad i na zbytek, dik
Marek
On Mon, Jan 27, 2014 at 7:45 PM, Jaroslav Buchta <jaroslav.buchta na hascomp.cz
> wrote:
> 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.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
>
>
> ------------------------------
> <http://www.avast.com/>
>
> Tato zpráva neobsahuje viry ani jiný škodlivý kód -avast! Antivirus<http://www.avast.com/>je aktivní.
>
>
> _______________________________________________
> HW-list mailing list - sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
>
>
------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20140127/586535ac/attachment.html>
Další informace o konferenci Hw-list