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