Hi there,
I am using a 13192-EVB board from Freescale. It has a MC9S08GT60 MCU. I am trying to get the DS1822 temp. sensor to communicate with the MC9S08GT60. I keep getting a temperature value of -255 all the time. Was wondering if someone can help me troubleshoot the issues I'm having. I'm using a 4.7 k pullup resistor and I am providing approx. 5V to power the DS1822. I am connecting a wire from pin 2 of the DS1822 to one of the IO pins (J107) on the 13192-EVB boards. I have pasted the code below to see if someone can help me. I am not sure if I have the bus speed configured correctly. I was using the Device Initialization Expert and I enabled the FLL clock to try to manually set the internal bus frequency to approx. 8 Mhz (7.776 Mhz is the closest I could get). I think that is what the code requires according to the delay function that I am using, but I could be wrong. Also in the device initialization expert I enabled PTA0 and PTA1 for input and output respectively with pullup enabled. The problem is when I compile the code and run it - I keep getting a uiTemperature value of -255. I don't know what the problem is. It seems to me like the DS1822 is just not communicating properly with the MCU and that the timing (delays) must be wrong. Would really appreciate all of your thoughts on this. Thanks.
Here are the definitions:
#define TRUE 1
#define FALSE 0
#ifndef PORTS_DQ
#define PORTS_DQ 1
#define DQ_RX PTAD_PTAD0
#define DQ_TX PTAD_PTAD1
#define DIR_DQRX 0
#define DIR_DQTX 1
#endif
Solved! Go to Solution.
Hello,
MMG135 wrote:Since I am just using Self Clocked Mode right now to obtain the 4 Mhz bus frequency. However, when running the code in Codewarrior I see that the actual frequency is around 3.7 Mhz when I am using the 13192-SARD boards and around 4.2 Mhz when I am using the 13192-EVB boards. So I'm guessing I would have to use the trim register in order to get this number as close to 4 Mhz as possible thereby ensuring that the delays are accurate. I'm assuming that the reason I'm not getting the 0x0550 (85 C) returned is due to slight timing issues. Would you be able to give me a rough idea of how to use the trim register. I understand from reading the manual that if my bus frequency is lower than expected(ie lower than 4Mhz), I would have to make the binary value of the ICGTRM lower and if the value of the bus frequency at compilation is higher than 4 Mhz, I must make the binary value in ICGTRM higher. Would I just determine the value in the ICGTRM register by trial and error or is there a certain formula? I'm assuming once I find the value I would just assign a value to ICGTRM in my main and that would take care of it? For example, ICGTRM=0x18; Am I right in assuming that I could use the ICGTRM register for either the 8 Mhz clock or the 243 khz clock? Of course, in this case I'm using the 8 Mhz clock which is divided by 2 to give me the 4 Mhz bus frequency. Thanks for your help.
The use of SCM mode is quite inappropriate for the timing accuracy that you require. I assumed that you would be using FEI mode, that requires trimming of the 243kHz reference. The trim calibration can be determined at the time of programming.
If you use an external crystal, or oscillator module ( I am not sure whether Zigbee usage mandates this accuracy), you would need to select either FEE or FBE mode. For a given crystal frequency, higher bus frequencies will be possible using FEE mode. The trim registers are not relevant to an external reference source.
Regards,
Mac
Hello,
The temperature measurement code previously posted might be located within main(), or alternatively within a separate function that would be called when a temperature measurement is required. In this form, no other processes may occur within the temperature conversion period.
Another alternative is to start a conversion within the function. Then, using a periodic timer interrupt, say every 10ms, to test for completion of the conversion, and then read the scratchpad when the conversion has finished. This process is more complex, but does allow other processing to occur, including Zigbee operations, during the conversion period.
Yet another possibility is to place other frequently executed furnctions within the wait loop itself, probably the same sequence of functions normally executed within the main loop. Once the temperature conversion has completed, further delays until the scratchpad is read are non-critical.
The method adopted will probably be that which best satisfies the overall project requirements.
Within the header file DS1822.h, you will find the definition of the typdef for SCRATCHPAD. This is a union between an array and a structure. The 16-bit value for temperature is an element of the structure, i.e. spad.s.temp
However, I have just realised that I did not take into account that the temperature data within the device scratchpad has little endian format (LS byte has a lower address), so the two bytes will need to be swapped. The first byte read should be placed within spad.array[1], and the second byte within spad.array[0] for the correct result.
A similar result would be achieved if the structure elements had a reversed sequence, and the array was filled, starting with the last element, i.e. for (i = 8; i + 1; i--)
Regards,
Mac
Hi Mac,
Thanks again for the post. Another question I had: since spad.array[0] and spad.array[1] are both 8 bits and I want to display the results via HyperTerminal for testing, I would need a function to convert from binary to string (or hex to string?) and then output the string to the hyperterminal. Could you recommend a function for doing this or perhaps a library to use with codewarrior that has a function to do this. Thanks for you help.
Hello,
There are library function that are capable of converting from binary to ASCII characters, e.g.sprintf(). However, these functions are complex and slow, needing a large amount of MCU resources - on this basis I suggest that you do not use them.
Additionally, the conversion of the temperature data is not straight forward. Negative values need to be handled, and the 12-bit data consists of an integer part (7-bits plus sign), and a fractional part (1 to 4 bits, depending on conversion resolution). When the fractional part is less than 4-bits, the unused bits have undefined state. So other preparations are needed prior to the ASCII conversion, and the integer and fractional parts are handled separately.
In the code shown below, the function T_to_ASCII() is my take on the conversion process. The code does not suppress leading zeros, and provides null terminated string data of the form "-xxx.xx\r\n".
I have also included a very simple function to send the string data via SCI module. This function exits only after all characters have been sent. Typically, I would not use this method, but would make use of interruts to send string data. But the interrupt method is somewhat more complex. I have not shown the initialisation code for the SCI module.
The following code represents the contents of a main.c file, to continuously provide consecutive temperature measurements. The other files for one-wire protocol were attached to a previous post. However, some macros were added to the file DS1822.h, in addition to reversing the sequence of the scratchpad elements.
#include <hidef.h> /* EnableInterrupts macro */#include "derivative.h" /* peripheral declarations */#include "One-wire.h"#include "DS1822.h"#ifdef __cplusplus extern "C"#endif// ASCII control characters:#define LF 10#define CR 13// Allow for multiple SCI modules in device:#ifndef SCID#define SCID SCI1D#define SCIBD SCI1BD#define SCIC1 SCI1C1#define SCIC2 SCI1C2#define SCIC3 SCI1C3#define SCIS1 SCI1S1#define SCIS2 SCI1S2#endif// Function prototypes:void MCU_init( void); // Device initializationbyte start_conv( void); // Start temperature conversionvoid get_temp( void); // Get results if conversion completevoid T_to_ASCII( int, byte, byte *); // Convert temperature to ASCIIvoid send_str( byte *); // Send string data to serial port// Global variables:SCRATCHPAD spad; // Copy of sensor scratchpad databyte conv; // Temperature conversion statusbyte buffer[20]; // Buffer for ASCII data/**********************************************************************/// START TEMPERATURE CONVERSIONbyte start_conv( void){ if (OW_reset()) { (void)OW_byteproc( SKIP_ROM); (void)OW_byteproc( CONVERT_T); conv = WAIT_CONV; // Conversion in progress } else conv = NO_DEVICE; // No device connected return conv;}/**********************************************************************/// TEST FOR CONVERSION COMPLETE - GET RESULTS FROM SCRATCHPAD// Polling function to be regularly called.void get_temp( void){ signed char i; if (conv == NO_DEVICE || // Exit if no device connected, or conv == NEW_RES) // Already new temperature result return; // Conversion status WAIT_CONV; test for conversion complete if (OW_byteproc( DUMMY)) { // Get results from scratchpad if so if (OW_reset()) { (void)OW_byteproc( SKIP_ROM); (void)OW_byteproc( READ_SPAD); // Read scratchpad data for (i = 8; i + 1; i--) // Fill array in reverse sequence spad.array[i] = OW_byteproc( DUMMY); conv = NEW_RES; // New result available } else conv = NO_DEVICE; // No device connected }}/**********************************************************************/// CONVERT TEMPERATURE READING TO ASCII STRING// The raw data received from the temperature sensor is a signed value,// and contains both integer and fractional parts. The integer part is// seven bits plus sign, and the fractional portion has a maximum of// four bits, a total of 12 bits that are right-aligned within the// 16-bit temperature value. Negative values are sign extended.// The fraction portion has 1 to 4 bits, depending on the resolution// setting within the scratchpad memory CONFIG register. If fewer than// four bits, the unused bits are undefined, and need to be zeroed.// The 'mode' parameter within this function determines the resolution.// mode = 0 -> 1-bit fraction, through to mode = 3 -> 4-bit fraction.void T_to_ASCII( int val, // Raw temperature reading byte mode, // Temperature resolution (0-3) byte *buf) // Pointer to buffer for ASCII data{ byte frac, t; if (val < 0) { val = -val; // Change to positive magnitude buf[0] = '-'; // Negative sign } else buf[0] = ' '; frac = (byte)(val & 0x000F); frac &= (0xFF << (3 - (mode & 0x03))); // Zero undefined bits t = (byte)(val >> 4); // Align 7-bit value buf[1] = t / 100 + '0'; // Hundreds digit t %= 100; // Remainder 0-99 buf[2] = t / 10 + '0'; // Tens digit buf[3] = t % 10 + '0'; // Units digit buf[4] = '.'; // Decimal point t = (byte)((word)frac * 25 + 2) / 4; // 2-digit fraction, with rounding buf[5] = t / 10 + '0'; // Tenths digit buf[6] = t % 10 + '0'; // Hundredths digit buf[7] = CR; // Line termination buf[8] = LF; buf[9] = 0; // Null termination for string}/**********************************************************************/// SEND STRING DATA TO SERIAL PORT (SCI)void send_str( byte *s){ byte *p; p = s; while (*p) { while (SCIS1_TDRE == 0); // Wait until SCI ready to send next byte SCID = *p++; // Send byte and increment pointer __RESET_WATCHDOG(); }}/**********************************************************************/void main(void){ MCU_init(); // Device Initialization SCI_init(); EnableInterrupts; for ( ; ; ) { __RESET_WATCHDOG(); if (conv == NEW_RES) // Previous result sent (void)start_conv(); // Start new temperature conversion get_temp(); // Polling function - end of conversion if (conv == NEW_RES) { // Process temperature result T_to_ASCII( spad.s.temp, spad.s.config >> 5, buffer); send_str( buffer); // Output string data } }}
.
// File: DS1822.h#ifndef _DS1822_H#define _DS1822_H// Temperature conversion status:#define NO_DEVICE 0 // No device connected#define WAIT_CONV 1 // Conversion in progress#define NEW_RES 2 // Conversion complete - new result available#define DUMMY 0xFF // Dummy send byte for 1-wire read// ROM commands:#define READ_ROM 0x33#define MATCH_ROM 0x55#define SEARCH_ROM 0xF0#define ALARM_SRCH 0xEC#define SKIP_ROM 0xCC// Function commands:#define CONVERT_T 0x44 // Convert temperature#define COPY_SPAD 0x48 // Copy scratchpad#define WRITE_SPAD 0x4E // Write scratchpad#define READ_SPAD 0xBE // Read scratchpad#define RECALL_EE 0xB8 // Recall EEPROM data#define READ_PS 0xB4 // Read power supply// Structures and unions:// Scratchpad format (reversed sequence):// The sequence reversal results in conversion of the// temperature reading from little endian to big endian.struct scratch { byte CRC; // Check byte byte unused[3]; byte config; // Conversion result size byte TLreg; // Lower threshold byte THreg; // Upper threshold word temp; // Temperature value};typedef union { byte array[9]; // Linear array struct scratch s; // Scratchpad format} SCRATCHPAD;#endif
Regards,
Mac
Hi Mac,
I tried to compile and run that code. It seems that I am not getting a response from the DS1822 device because nothing was outputted serially to the Hyper Terminal. So, I tried modifying the serial code a little bit and I'm still getting all zeros. I just tried to modify the code so that I could output the LSB to at least see if I'm getting any output at all from the DS1822. It seems that I am not. I then tried various voltages to power the DS1822 from about 3.5 to 5.3 V and different values for the pullup resistors(4.7k, 10k, 1.5k) but nothing seems to work. I am starting to suspect that I may have burned out my DS1822's since they did get very hot not too long ago. Also, is it normal for the voltage at the Vdd pin to be the same as at the DQ pin or does that indicate a short somewhere? I ordered some new DS1822's to test. Also, I do have some DS1822-PAR on hand which are the parasitic versions. How would I modify the code to test a parasitic version of the DS1822? Would I still need an external 4.7k pullup or would I just use the internal pullup on PIN C5 of the MC9S08GT60? My understanding is that I would just have to enable this pullup during the conversion process? I don't think I would be able to use polling to check if the conversion is done either. Other than that, would the code for parasitic mode be the same? I have attached my modifications to the code to see if this should actually properly display the LSB of the temperature serially via Hyper Terminal. Thanks for your input and help in this matter.
Hello,
I think that you will need to perform the diagnostics in stages. As previously suggested, you will need an oscilloscope to assist this process. Note that the DS1822 should be powered from the same supply as the MCU, and the pullup resistor should also be connected to the same source. The standard GP output pin should easily be capable of sinking the current from an external 4k7 pullup. The internal pullup within the MCU alone, may be too high a resistance value to provide a short enough rise time for the waveform.
You should firstly check that you are getting the full voltage swing at the GPIO pin, to ascertain that no other component on the board is connected to the same pin, and maybe causing a problem.
The next step would be to check that the reset pulse has the correct timing, and to observe whether a presence pulse is being returned. If so, it is unlikely that the device is faulty.
The next stage would be to observe whether return temperature data is present, containing a mix of 1's and 0's pulse widths.
Ultimately, you would need to check that the SCI module is sending string data with the correct baud rate. This can be tested quite independently of the temperature sensor - simply create some constant string data, and check whether this can be received by Hyperterminal.
You will need to trim the reference frequency to achieve the required bus frequency. I suspect that this may not be happening. A frequency error here will affect both one-wire timing and the SCI baud rate. The trim value can be determined during the programming process, and placed within specific flash registers. However, during initialisation this data then needs to be transferred into the oscillator module trim register(s) to set the bus frequency.
Regards,
Mac
Hi Mac,
Regarding the SCI module, I have definitely verified that it is working. I set a variable to a known value 0x99 and then used the conversion to ascii function and then sent the data to the serial port and it definitely shows up correctly in Hyperterminal. I put it in a loop so it would keep sending this value. So after I verified this, that is when I tried to take out the test value and just let it send the temperature information(LSB) but it kept coming back with zeros. This is when I suspected the sensor may have been faulty. I agree with you 100% that I need to do more troubleshooting with the oscilloscope to verify that the sensor is the problem 100%.
I have some good news. I connected the DS1820-PAR sensor (the parasitic-only version of the DS1822) and I am getting a response finally. For byte 0 and 1 of the temperature I am getting 0x16 and 0x28 respectively. This is when I try to read the temperature bytes individually. If I use the conversion function I seem to be getting a result of 193. This is much better than before when it appeared that I was getting random values. These values are now constant and do not change which is a good sign. It appears that now, I may just have to adjust the timing. I will attach my code for you to take a look at in my next post.
Here is the code I used. The part that is commented out is the code I used to just get the first and second byte of temperature information, spad.array[0]=16, spad.array[1]=28. This used the first ASCII conversion function. The code that is not commented out is what is used to get the 193 value, which I'm assuming should be the converted temperature value in degrees C. I suspect what you said regarding the need to use the trim register is what I need to work on next. Since I am just using Self Clocked Mode right now to obtain the 4 Mhz bus frequency. However, when running the code in Codewarrior I see that the actual frequency is around 3.7 Mhz when I am using the 13192-SARD boards and around 4.2 Mhz when I am using the 13192-EVB boards. So I'm guessing I would have to use the trim register in order to get this number as close to 4 Mhz as possible thereby ensuring that the delays are accurate. I'm assuming that the reason I'm not getting the 0x0550 (85 C) returned is due to slight timing issues. Would you be able to give me a rough idea of how to use the trim register. I understand from reading the manual that if my bus frequency is lower than expected(ie lower than 4Mhz), I would have to make the binary value of the ICGTRM lower and if the value of the bus frequency at compilation is higher than 4 Mhz, I must make the binary value in ICGTRM higher. Would I just determine the value in the ICGTRM register by trial and error or is there a certain formula? I'm assuming once I find the value I would just assign a value to ICGTRM in my main and that would take care of it? For example, ICGTRM=0x18; Am I right in assuming that I could use the ICGTRM register for either the 8 Mhz clock or the 243 khz clock? Of course, in this case I'm using the 8 Mhz clock which is divided by 2 to give me the 4 Mhz bus frequency. Thanks for your help.
Hello,
MMG135 wrote:Since I am just using Self Clocked Mode right now to obtain the 4 Mhz bus frequency. However, when running the code in Codewarrior I see that the actual frequency is around 3.7 Mhz when I am using the 13192-SARD boards and around 4.2 Mhz when I am using the 13192-EVB boards. So I'm guessing I would have to use the trim register in order to get this number as close to 4 Mhz as possible thereby ensuring that the delays are accurate. I'm assuming that the reason I'm not getting the 0x0550 (85 C) returned is due to slight timing issues. Would you be able to give me a rough idea of how to use the trim register. I understand from reading the manual that if my bus frequency is lower than expected(ie lower than 4Mhz), I would have to make the binary value of the ICGTRM lower and if the value of the bus frequency at compilation is higher than 4 Mhz, I must make the binary value in ICGTRM higher. Would I just determine the value in the ICGTRM register by trial and error or is there a certain formula? I'm assuming once I find the value I would just assign a value to ICGTRM in my main and that would take care of it? For example, ICGTRM=0x18; Am I right in assuming that I could use the ICGTRM register for either the 8 Mhz clock or the 243 khz clock? Of course, in this case I'm using the 8 Mhz clock which is divided by 2 to give me the 4 Mhz bus frequency. Thanks for your help.
The use of SCM mode is quite inappropriate for the timing accuracy that you require. I assumed that you would be using FEI mode, that requires trimming of the 243kHz reference. The trim calibration can be determined at the time of programming.
If you use an external crystal, or oscillator module ( I am not sure whether Zigbee usage mandates this accuracy), you would need to select either FEE or FBE mode. For a given crystal frequency, higher bus frequencies will be possible using FEE mode. The trim registers are not relevant to an external reference source.
Regards,
Mac
Hi Mac,
Thanks for the reply. Before SCM I was using the following register settings to obtain a bus frequency around 4.19 Mhz.
ICGC1=0x38;
ICGC2=0x00;
while(ICGS1_LOCK==0);
Initially I was using a FLL using device initialization to obtain the required frequency. So I was just trying different clock settings out. Now that I understand I must use FEI mode that makes things much clearer. I should perhaps use the following though:
ICGC1=0x28; // set prescale to 64 and FLL internal.
ICGC2=0x21; //sets N=4, R=2 to obtain 4 Mhz bus
while(ICGS1_LOCK==0);
Then after this, I should just set the value in the ICGTRM register to make the bus freq. very close to 4 Mhz. Am I correct in my procedure? Thanks for your help.
Hello,
The following is an example of some ICG initialisation code that I have previously used. I think that it may have been based on the code generated by PE device initialisation tool. It assumes that the non-volatile trim value is calibrated and programmed during the normal code programming process. This is the usual practise.
Of course, the detail of your setup requirement may differ from mine.
// Part of MCU_init.h/* ICG module FEI mode: Trimmed bus frequency = (Fref/7) * 64 * N/R/2 = (1.111E6 * N/R) Hz = 8.888 MHz N = 2*(MFD + 2); R = 2^RFD*/ #define MFD 6 // Multiplication factor N = 16#define RFD 1 // Reduced freq. divider R = 2#define BUSFREQ 1111000 * 16 / 2
// Part of MCU_init.c /* Initialise ICG module FEI mode */ ICGC1 = 0x08; /* 00001000 ||||||+-- LOCD Loss-of-clock detect enabled |||||+--- OSCSTEN Oscillator disabled in off mode |||++---- CLKS Select FEI mode ||+------ REFS Don't care - no external reference |+------- RANGE Don't care +-------- HGO Don't care */ ICGC2 = 0x08; // Reset on loss-of-clock ICGC2 |= (MFD << 4) | RFD; /* Initialize OSCTRIM register from flash memory location */ ICGTRM = *(unsigned char *far)0xFFBE; if (ICGTRM == 0xFF) // Test for programmed trim value ICGTRM = 0x80; // Set nominal value if not#ifndef _FCS while (!ICGS1_LOCK); // Wait for FLL lock#endif
Regards,
Mac
Hi Mac,
Thanks for that code example. It definitely helps clarify things. If I understand this correctly I would change the ICGC1 and ICGC2 to the following:
ICGC1 = 0x4C;
/* ICGC2: LOLRE=1,MFD2=1,MFD1=0,MFD0=1,LOCRE=1,RFD2=0,RFD1=1,RFD0=0 */
ICGC2 = 0xDA;
//ICGTRM = *(unsigned char*far)0xFFBE; /* Initialize ICGTRM register from a non volatile memory */
ICGTRM = NVICGTRM - 15; //copy the value from non-volatile memory to the ICGTRM register.
if (ICGTRM == 0xFF) // Test for programmed trim value
ICGTRM = 0x80; // Set nominal value if not
while(!ICGS1_LOCK) { /* Wait */
}
This was generated from Device Initialization for 3.88 Mhz. I added the if statement to check if the trim value has been programmed and then to set it to a nominal value if not. The statement above that is used to copy the value from non volatile memory and then increase the frequency slightly since it's set for 3.88 and I need 4.0 Mhz. I assume these two lines do the same thing:
ICGTRM = *(unsigned char*far)0xFFBE; /* Initialize ICGTRM register from a non volatile memory */
ICGTRM = NVICGTRM; //copy the value from non-volatile memory to the ICGTRM register.
Let me know if the above code seems good to you for getting very close to a 4.0 Mhz bus speed using the ICGTRM register.
In another note, I will try implementing this code later on today. Yesterday, I was getting some promising results with the DS1822. Since I did not yet implement this code, the timing was a little off I'm assuming but it was returning values that seem almost legitimate. For example, I was getting 81.00, 65.00, and 33.00 repeatedly. I'm assuming that 81 may be the default value (85) but it maybe is just a little bit off since the bus speed is not yet exactly 4.0 Mhz. The 33 value may be my temperature value that I need (it's probably a little bit off as well due to bus clock) but it is still in the right ballpark. What do you think? Thanks again for all your help and let me know if the above code for using ICGTRM is correct.
Hello,
Why do you actually need to use a bus frequency of 4.00 MHz?
Since the actual BUSFREQ value may be defined, the one-wire delays should be able to use other bus frequencies. For higher bus frequencies, some of the longer delays may need to be done in a couple of stages, or alternatively the delay function may be redesigned to specifically suit a higher bus frequency.
The more critical consideration will be the baud rate for the SCI module. You do not say what baud rate you require. For a standard baud rate of 9600 bit/s, a bus frequency of 4.00 MHz is suitable, but so are many other potential bus frequencies that make use of the standard trim setting calibration. The following trimmed bus frequencies can all provide a rate of 9600 bit/s with an error less than 0.5 percent.
4.444, 5.555, 8.888, 9.999, 11.110, 13.332, 15.554, 17.776 and 19.998 MHz.
My personal preference would be to use the standard trim calibration, without the need to empirically deternine the trim adjustment for a "non-standard" reference frequency (i.e. 250kHz in lieu of 243kHz).
Yet another possibility is to utilize the CLK0 output from the wireless modem as an external reference for the MCU (FEE or FBE mode). But the modem would need to be active during the temperature measurement process, and during SCI communications, (if applicable).
MMG135 wrote:statement above that is used to copy the value from non volatile memory and then increase the frequency slightly since it's set for 3.88 and I need 4.0 Mhz. I assume these two lines do the same thing:
ICGTRM = *(unsigned char*far)0xFFBE; /* Initialize ICGTRM register from a non volatile memory */
ICGTRM = NVICGTRM; //copy the value from non-volatile memory to the ICGTRM register.
I could not find the macro for NVICGTRM within the standard device header file (maybe I have an earler version). For both lines to provide the same result, there would obviously need to be a macro definition in accordance with:
#define NVICGTRM *(unsigned char*far)0xFFBE
Regards,
Mac
Hi Mac,
Thanks for your post. Regarding the baud rate, I was using 9600 for the standalone DS1822 code. This was using a bus frequency of 4 Mhz initially but I was able to modify it to use an 8 Mhz bus frequency. To do this, I just modified the code as you suggested to add successive delays of the maximum amount until I reached the required delay amount (eg. 480 us). My BR values for 9600 with 4 Mhz was 0x1A and with 8 Mhz and 9600 it was 0x34. The SCI module worked perfectly for both the 8 Mhz and 4 Mhz standalone DS1822 code. Now that I have this 'standalone' application working I want to try to include this code in the generic Zigbee application (smac-per-tx) provided with the Beekit software. There are various other sample Zigbee applications that may work better for me to integrate this DS1822 into but I haven't found any code simpler than the smac-per-tx application as of yet. In your previous posts, I think you may have anticipated the issues I am having now. I tried to simply add the header files you created for the DS1822 into the smac-per-tx(Zigbee) project. Then in the main I simply tried to call the temperature conversion function and copy the result into a variable that I could transmit using the Zigbee code already in place.
You mentioned:
Another alternative is to start a conversion within the function. Then, using a periodic timer interrupt, say every 10ms, to test for completion of the conversion, and then read the scratchpad when the conversion has finished. This process is more complex, but does allow other processing to occur, including Zigbee operations, during the conversion period.
Perhaps this is related to my problem because I have not tried creating a periodic timer interrupt that will poll for conversion and then read the scratchpad. It seems as though either the timing for talking to the DS1822 is off when I try to use the working code in the Zigbee application or a second alternative may be that I am not calling the temperature conversion function at the appropriate time. Would you be able to give me an idea of how I would create a simple periodic timer interrupt every 10 ms to test for completion of the temperature conversion and then read the scratchpad afterwards. This may be the root of my problem when I try to use the DS1822 code in the Zigbee application.
You will also need to ascertain whether the global disabling of interrupts for the periods necessary for one-wire operation, will give problems for Zigbee operation.
I have tested this out and it seems that globally disabling interrupts does not affect Zigbee operation. I am using the same header files that you posted and just calling the DS1822 functions you posted which disable and then enable interrupts again and the Zigbee operations seem to continue undisturbed. I have confirmed that I am able to send and receive simple Zigbee packets while I am making use of the temperature conversion function.
Yet another possibility is to utilize the CLK0 output from the wireless modem as an external reference for the MCU (FEE or FBE mode). But the modem would need to be active during the temperature measurement process, and during SCI communications, (if applicable).
It seems that the Zigbee application may be using this approach but I am not 100% certain. I have posted the code to see if perhaps you could take a quick look and see where I may have gone wrong in my approach. After I added the previously mentioned DS1822 header files to the project and called the temperature conversion function in main, the code compiles just fine but I do not receive the temperature information on the receiving board. However, if I replace the temperature function with just regular integer values I can receive these values just fine on the receiving board via Hyper Terminal.
I should also mention a few more things about the code I posted below. In the temperature conversion function I found that for the DS1822's I needed to start reading from byte 0 and 1 first and this would give me the correct temperature information. This is why I changed this part of the temperature converstion function but everything else works perfectly. I tried calling the temperature conversion function from multiple places within the zigbee application but nothing seems to work maybe for the reasons mentioned already. The two places where the zigbee application sends information, from what I understand, are shown below. They can also be seen in the code in attached. Thanks for your help. I greatly appreciate it.
switch (app_status) { case INITIAL_STATE: //Walk the LEDs //For TX LED1 = LED_OFF; //Turn off all LEDs LED2 = LED_OFF; LED3 = LED_OFF; LED4 = LED_OFF; LED1 = LED_ON; //Lights LED1 for (loop = 0; loop < LED_DELAY; loop++); LED1 = LED_OFF; LED2 = LED_ON; //Lights LED2, Turns off LED1 for (loop = 0; loop < LED_DELAY; loop++); LED2 = LED_OFF; LED3 = LED_ON; //Lights LED3, Turns off LED2 for (loop = 0; loop < LED_DELAY; loop++); LED3 = LED_OFF; LED4 = LED_ON; //Lights LED4, Turns off LED3 for (loop = 0; loop < LED_DELAY; loop++); LED4 = LED_OFF; //Turns off LED4 LED1 = LED_ON; app_status = IDLE_STATE; //Switch app status to TX_STATE temp=Temperature(); tx_data_buffer[0] = 0; tx_data_buffer[1] = temp; tx_data_buffer[2] = temp; tx_data_buffer[3] = temp; tx_data_buffer[4] = temp; tx_data_buffer[5] = temp; tx_data_buffer[6] = temp; tx_data_buffer[7] = temp; tx_data_buffer[8] = temp; tx_data_buffer[9] = temp; tx_packet.u8DataLength = 10; //Set the data length of the packet. in this case, 6. packet_count=0; break;
/* See if START TX has been hit */ if ((gu16Events & KBI2_EVENT) != 0) { #if BUZZER_ENABLED BUZZER = BUZZER_ON; #endif delay(10); #if BUZZER_ENABLED BUZZER = BUZZER_OFF; #endif gu16Events &= ~KBI2_EVENT; /* Clear the event */ packet_count=0; setLedsMode(LED_DIGIT_MODE, (UINT16) 8421, 10, LED_NO_FLAGS); temp=Temperature(); tx_data_buffer[0] = 0; tx_data_buffer[1] = temp; tx_data_buffer[2] = temp; tx_data_buffer[3] = temp; tx_data_buffer[4] = temp; tx_data_buffer[5] = temp; tx_data_buffer[6] = temp; tx_data_buffer[7] = temp; tx_data_buffer[8] = temp; tx_data_buffer[9] = temp; //Set the data length of the packet. in this case, 6. tx_packet.u8DataLength = 10; packet_count=0; app_status = TX_STATE; }
Hello,
If you have any specific SMAC or Zigbee issues, probably better to start a new thread for these. These subjects are not within my previous personal experience.
Why not use a bus frequency of 8.888 MHz, instead of 8.00 MHz. You can then use the standard trim calibration.
I assume that you are transmitting the temperature data as a binary value with positive sign, and are ignoring the fractional part of the original data. Are you not interested in temperatures below zero Celsius? What is your output should the measured temperature be a negative value? With multiple temperature sensors, how do you intend to identify the particular sensor?
Why not consider sending the temperature data packet as an ASCII sequence, similar to the previous SCI example.
If you intend using parasitic power mode, you will not be able to test for the completion of a conversion, but would simply allow sufficient time for conversion to be completed.
There still appears some confusion over the updated code snippet that i posted (message 23). The MS byte of the temperature data is actually placed in spad.array[7], and the LS byte in spad.array[8]. Access to the data using the union element spad.s.temp should give the correct endianness.
With the requirement of only ten measurements per day, I assume the MCU will be in Stop2 mode for most of the time (with the wireless modem section also in a low power state). You will need to wake up the MCU at timed intervals, but this will actually be much more frequent than the 144 minutes between temperature readings. You will therefore need to count the number of wakeups until 144 minutes has elapsed. With Stop2 mode, the RTI can remain operative for wakeup timing, but has limited timing accuracy. I am not sure whether any additional timing resources are available within the wireless modem section.
I do not have prior knowledge of the Search ROM algorithm used by the DS1822.
Regards,
Mac
Hi Mac,
Thanks for the reply.
I assume that you are transmitting the temperature data as a binary value with positive sign, and are ignoring the fractional part of the original data. Are you not interested in temperatures below zero Celsius? What is your output should the measured temperature be a negative value? With multiple temperature sensors, how do you intend to identify the particular sensor?
For the moment, I only need positive temperature values although negative values may be a nice feature to have later. I was just using the positive values for testing purposes. Thanks for clarifying that the temperature is stored in spad.array[8] and spad.array[7]. I will try to use this information and test to see if I am getting negative temperature values after this. I would definitely prefer to have negative and positive temp. values as opposed to just positive ones.
If you intend using parasitic power mode, you will not be able to test for the completion of a conversion, but would simply allow sufficient time for conversion to be completed.
I tried to test the code in parasitic power mode but all I am getting is 85 (the default temp. value) and nothing else. I have tried different delays and everything but for some reason it isn't working. Is there some extra code I need to add to what you already posted in order for it to work in parasitic power mode? Of course I ground both the Vdd and GND pins and I have a 4.7k resistor between +3V from the MCU and the DQ (data bus). I was reading elsewhere that I may need an additional transistor in some cases if the single 4.7k pullup is not sufficient?
Here is what I tried:
First I make the following definition:
#define OW_PULLUP OW_PORT=1; OW_PORTDD=1;
UINT8 Temperature(void) {UINT8 temperature;UINT8 msb, lsb;int i;int j; // Start temperature conversion: if (OW_reset()) { (void)OW_byteproc( SKIP_ROM); (void)OW_byteproc( CONVERT_T); OW_PULLUP //delay for(i=0; i<500; i++) { for(j=0; j<700; j++); } } // Get results from scratchpad: if (OW_reset()) { (void)OW_byteproc( SKIP_ROM); (void)OW_byteproc( READ_SPAD); // Read scratchpad data //for (i = 8; i >=0; i--) { //spad.array[i] = OW_byteproc( DUMMY); spad.array[0] = OW_byteproc(DUMMY); //Temperature LSB spad.array[1] = OW_byteproc(DUMMY); //Temperature MSB msb = spad.array[1] << 4; /* 0000 0101 left shift by 2 bits is 0001 0000 */ //printf("\n Left shift by 2 bits d1 << 2 = %d", d3); lsb = spad.array[0] >> 4; /* 0000 0101 right shift by 2 bits is 0000 0001 */ //printf("\n Right shift by 2 bits d1 >> 2 = %d", d4); temperature = msb | lsb; /* 0101 & 0110 = 0100 (=4) */ //printf("\n Bitwise AND d1 & d2 = %d", d5); } return temperature; }
Will this approach work for parasitic mode? Instead of setting the GPIO as an output and driving the bus high, I also tried just leaving it in a High-Z state but I had the same problem. I am just getting 85 and no other value. Can you think of what else might be giving me a problem? Thanks for your help.
Also I found this good description on the Search ROM algorithm from Maxim. It seems that it requires a read_bit() and write_bit() function specifically, as well as the read_byte() and write_byte() functions. So I'm assuming the one wire code right now with just the OW_byteproc (read/write byte) and PROC_BIT won't work with this algorithm. If I try to send for example a byte of 0x01 it will send 7 zero's first and then a 1 at the end, instead of just a 1? Am I correct in assuming this? If so, I will probably need to re-write two more functions read_bit() and write_bit(). Here is the link to the article I am referring to: http://www.maxim-ic.com/app-notes/index.mvp/id/187.
Here is the portion of the code I am referring to:
int OWSearch(){ int id_bit_number; int last_zero, rom_byte_number, search_result; int id_bit, cmp_id_bit; unsigned char rom_byte_mask, search_direction; // initialize for search id_bit_number = 1; last_zero = 0; rom_byte_number = 0; rom_byte_mask = 1; search_result = 0; crc8 = 0; // if the last call was not the last one if (!LastDeviceFlag) { // 1-Wire reset if (!OWReset()) { // reset the search LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; return FALSE; } // issue the search command OWWriteByte(0xF0); // loop to do the search do { // read a bit and its complement id_bit = OWReadBit(); cmp_id_bit = OWReadBit(); // check for no devices on 1-wire if ((id_bit == 1) && (cmp_id_bit == 1)) break; else { // all devices coupled have 0 or 1 if (id_bit != cmp_id_bit) search_direction = id_bit; // bit write value for search else { // if this discrepancy if before the Last Discrepancy // on a previous next then pick the same as last time if (id_bit_number < LastDiscrepancy) search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == LastDiscrepancy); // if 0 was picked then record its position in LastZero if (search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if (last_zero < 9) LastFamilyDiscrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if (search_direction == 1) ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= ~rom_byte_mask; // serial number search direction write bit OWWriteBit(search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask <<= 1; // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if (rom_byte_mask == 0) { docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC rom_byte_number++; rom_byte_mask = 1; } } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if (!((id_bit_number < 65) || (crc8 != 0))) { // search successful so set LastDiscrepancy,LastDeviceFlag,search_result LastDiscrepancy = last_zero; // check for last device if (LastDiscrepancy == 0) LastDeviceFlag = TRUE; search_result = TRUE; } } // if no device found then reset counters so next 'search' will be like a first if (!search_result || !ROM_NO[0]) { LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; search_result = FALSE; } return search_result;}
Here are the functions read_bit() and write_bit() that I put together. Let me know if you think they are ok.
byte read_bit(void){DisableInterrupts;byte i;OW_PINLOW;OW_PINHIGH;DELAYUS(10);i=OW_PINTEST;DELAYUS(48);EnableInterrupts;return i; }void write_bit(byte bitval){DisableInterrupts;OW_PINLOW;if(bitval==1) OW_PINHIGH;DELAYUS(58);OW_PINHIGH;EnableInterrupts;}
Perhaps I would also be able to do this:
byte OW_bitproc( byte val){ byte count = 1; byte rxbuf = 0; __asm {LP1: lsr val // CF = send bit (LSB) jsr PROC_BIT // Process bit write/read sequence ror rxbuf // Save return bit dbnz count,LP1 // Loop for next bit } return rxbuf;}
Would I still be able to use OW_bitproc(DUMMY) to read a bit rather than a byte and would (void)OW_bitproc(0x01) send a bit value of 1 and (void)OW_bitproc(0x00) send a bit value of 0?
Hello,
I cannot see a problem with your strong pullup setting, however you should check that the ouput remains constant close to a 3.3 volt level for the whole of the conversion period.
Jim D. - There should be no need for an external MOSFET to provide the strong pullup, since a P-channel MOSFET is already intrinsic to a port pin that is set as an output.
To read a single bit and to write a single bit, I might suggest the following untested functions:
#include <intrinsics_hc08.h>// Return read status for a single one-wire bit:byte OW_bitread( void){ __asm sec; PROC_BIT(); return __isflag_carry();}// Write single bit to one-wire device:void OW_bitwrite( byte state){ __asm lsr state; PROC_BIT();}
Regards,
Mac
Hi Mac,
Thanks for the reply. I tested the read and write bit functions you posted and they seem to work fine with the Search ROM algorithm! I am still having issues with parasitic power though for some reason. External power mode works fine. I will check if I'm getting a constant 3.3 V from the GPIO pin on the 13192-EVB board during the conversion period. I'll let you know the results. I have read somewhere that in order for the DS1822 to charge the internal capacitor in parasitic mode, the DQ line has to be at least 2.8 V. Also, the wiring on the DS1822 datasheet suggests to connect the MOSFET from another GPIO pin to the data line (DQ) line. I'm guessing connecting another MOSFET would have no effect if there is already a MOSFET on the GPIO pin when it is connected as an output? Another thing I have noticed is that most people are using a 5V supply to power the DS1822's in parasitic mode. I'm not sure how much of a difference using 3V instead of 5V would make. The specs on the DS1822 do say it can take 3V but I'm not sure if there are other requirements needed if I use 3 V instead of 5 V. It is also possible I am connecting something wrong. For example, in parasitic mode I still have a 'separate' 3V source (from the internal 3V source on the EVB board) going through a 4.7k resistor to the DQ line which goes into the GPIO pin. The GND and Vcc pins are grounded. However, then I am also driving the GPIO pin high as an output during the conversion period to provide extra power during this time. This is all on t\\he same GPIO pin. Is it possible I need to use separate GPIO pins for this?
Also, here is the thread I started regarding the Zigbee issues: https://community.freescale.com/message/92396#92396.
I have not received any responses yet. I was thinking that I could just try reading over the custom application example found in the Beestack Development Guide. It was using the onboard accelerometers and transmitting the data via Zigbee to another EVB or SRB board. I think my main problem will be with the interrupt functions. I will try to make some modifications to the custom application, including the interrupt functions if needed so that once a temperature conversion is done it will generate an interrupt and then the data will be sent via Zigbee to another SARD or EVB board. Here is a link to the document in case you wanted to take a look: http://www.freescale.com/files/rf_if/doc/user_guide/BSADG.pdf
One more thing I should mention: I have read that for parasitic power 'active' pullup must be used. I'm assuming this means that I can't just set the GPIO pin as input (high-z) state and let the bus go high this way. I must actually force the data bus high by setting the GPIO pin as output and driving the bus high that way using OW_PORT=1; OW_PORTDD=1.