This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC2138 timer1 match register int setting without ISR code

I need three time period for onewire data reading. Without writing any ISR and can I get required time periods by polling M0, M1 and M2 match register interrup flags. Following code is what I am working on and it doesn't work. Is there any missing settings else?

#define Presc      14
//--------------------------16 bit write ----------------------------
void onewire_write(short int bayt, short int data)      // 6, 54, 10
{
 short int count, bits;
 bits = bayt * 8;
#define AB      6
#define BC      60
#define DD      10
#define M0_i    1                  // Bit <2:0> <s:r:i>   Stop,Reset,Interrupt
#define M1_i    1<<3           // Bit <5:3> <s:r:i>   "
#define M2_irs  7<<6           // Bit <8:6> <s:r:i>   "
 T1PR  = Presc;                    // Prescale 15, 60 MHz CClock, 15 MHz PCLCK
 T1MR0 = AB;                   // Wait this long
 T1MR1 = AB+BC;                // Wait this long
 T1MR2 = AB+BC+DD ;            // Wait this long
 T1MCR = M0_i | M1_i | M2_irs; // Interrupt,stop and reset settings of Match regs

 T1TCR = 0x02; // Reset timer1

 for (count=0; count<bits; ++count)
 {
  output_low();
    T1TCR = 0x01;              // timer1 starts
    while(!(T1IR & 1));        // Wait for int flag
  if ( data&1 != 0 ) output_float(); // write 0 or 1
    data >>= 1;
    while(!(T1IR & 2));        // Wait for int flag
  output_float();              // set 1-wire high again,
    while(!(T1IR & 4));        // Wait for int flag
    T1IR = 0x07; // Clear M2, M1, M0 interrupts

 }
}

  • for (count=0; count<bits; ++count)
    

    changed to

    for (count=0; count<bits; count++)
    

    Now works :)

  • Are you sure?

    Then it's time to report a bug to Keil. Preincrement or postincrement should not matter in this case, except that you may slightly affect the code optimization resulting in a difference in one or a few clock cycles/iteration.

    What does the assembler output looks like for the two alternatives?

  • You are right. index starts from 0. So what I did ? (its too late in the night and I am tired :) )

    I changed 16 bit reading to 8 bit reading and writing functions. Doing so, writing or reading 16 bit at once procedure changed to double (2x8 bit) write and read procedure. Reading 2 byte from ds18b20, I constructed single integer value from 2 byte (char type). And then converted to floating point number.

    What I supposed as a bug is that there might be improper timer1 regs settings. I worked around it. I think problem was originated from short int (return value of 16 bit read function) to int conversion.

    I have red your post at another thread suggesting comparision of t1tc and t1mr0 regs. I also followed that recommendation and got satisfactory result, then walked back again to my original code and it worked. The only change could possibly affect the algorithm was the modification of ++count to count++ of the above quoted code. I got confused :) Here is the final working functions:

    #define Presc      14
    //--------------------------16 bit write ----------------------------
    void onewire_write(unsigned char data)  // 6, 54, 10
    {
     char count;
    #define AB      6
    #define BC      60
    #define DD      10
    #define M0_i    1                  // Bit <2:0> <s:r:i>   Stop,Reset,Interrupt
    #define M1_i    1<<3           // Bit <5:3> <s:r:i>   "
    #define M2_sri  7<<6           // Bit <8:6> <s:r:i>   "
     T1PR  = Presc;                    // Prescale 15, 60 MHz CClock, 15 MHz PCLCK
     T1MR0 = AB;                   // Wait this long
     T1MR1 = AB+BC;                // Wait this long
     T1MR2 = AB+BC+DD ;            // Wait this long
     T1MCR = M0_i | M1_i | M2_sri; // Interrupt,stop and reset settings of Match regs
    
     T1TCR = 0x02; // Reset
    
      for (count=0; count<8; count++)
     {
      output_low();
        T1TCR = 0x01;              // timer1 starts
        while(!(T1IR & 1));        //while(T1MR0!=T1TC); // Wait for int flag
      if ( data&1 != 0 ) output_float(); // write 0 or 1
        while(!(T1IR & 2));        //while(T1MR1!=T1TC); // Wait for int flag
      output_float();              // set 1-wire high again,
        while(!(T1IR & 4));        //while(T1MR2!=T1TC); // Wait for int flag
        T1IR = 0x07; // Clear M2, M1, M0 interrupts
        data >>= 1;
     }
    }
    
    //-------------------------- 16 bit read ----------------------------
    
    char onewire_read()   // 6, 9, 55
    {
     unsigned char count, data=0;
    #define AA      4
    #define EE      10
    #define FF      55
    #define M0_i    1                  // Bit <2:0> <s:r:i>   i = interrupt
    #define M1_i    1<<3           // Bit <5:3> <s:r:i>   r = reset
    #define M2_sri  7<<6           // Bit <8:6> <s:r:i>   s = stop
     T1PR  = Presc;                    // Prescale 15 60 MHz CClock, 15 MHz PCOLCK
     T1MR0 = AA;                   // Wait this long
     T1MR1 = AA+EE;                // Wait this long
     T1MR2 = AA+EE+FF ;            // Wait this long
     T1MCR = M0_i | M1_i | M2_sri; // Interrupt,stop and reset
    
     T1TCR = 0x02; // Reset
    
      for (count=0; count<8; count++)
     {
        data >>=1;
      output_low();
        T1TCR = 0x01;              // timer1 starts
        while(!(T1IR & 1));        //while(T1MR0!=T1TC); // Wait for int flag
      output_float();              // now let 1-wire float (high by pullup resistor)
        while(!(T1IR & 2));        //while(T1MR1!=T1TC); // Wait for int flag for master sampling
      if( input() != 0 ) data |= 0x80;
        while(!(T1IR & 4));        //while(T1MR2!=T1TC); // Wait for int flag
        T1IR = 0x07; // Clear M2, M1, M0 interrupts
     }
     return( data );
    }
    


    Calling these functions:

    onewire_reset();
     onewire_write(0xCC);
     onewire_write(0xBE);
     t1 = onewire_read();
     t2 = onewire_read();
     tt= ((int) t2<<8) | ((int)t1 & 0xFF);
     result = (float)tt / 16.0;  //defauld conf. 12 bit resolution
     return(result);
    


    This is my first step to ARM7 and Keil and LPCs, so I do not know its assembly.

    I hope this clarrify my confusion :)

    Regards

  • Sorry, but the time is quite late - 00:40, but a couple of quick notes.

    You should really consider doing your shifts using unsigned integers. Shifts with signed negative integers is not so fun because of sign extension. It is better to stay with unsigned data all the way until you have retrieved and combined the full set of bits, and then optionally type cast to a signed value.

    Another thing - do consider the value of your comments.

    T1MR0 = AA;                   // Wait this long
     T1MR1 = AA+EE;                // Wait this long
     T1MR2 = AA+EE+FF ;            // Wait this long
    


    "this long" isn't exactly descriptive. Why not describe what you are waiting for in the onewire bit cycle.

    It is a great idea to use version control software for your code, allowing you to compare the full set of differences between to versions. That will often answer that magic question of "I don't know what I did, but now it works". If it doesn't, then it's likely that both the old and the new code aren't working, but that one of the versions may seem to work under specific, limited, conditions.

  • I just had to quickly revisit this thread.

    Are you aware that you don't need to add any floating point support to handle the fractional temperature from the DS18B20 sensor? If you want the temperature with three decimal digits, then you can multiply the integer part of the temperature with 1000 and then check the contents of the least significant four bits. The are then worth 500, 250, 125 and 62(.5).
    So if the integer part was 25 and the fraction had the value 0110, you would get:
    25*1000 = 25000.
    Then add 0*500 + 1*250 + 1*125 + 0*62.
    This would give 25375, which represents 25.375 degrees.
    Just remember that if the temperature was negative, then you should change sign of the temperature before handling the fractional part.

    And another thing - you don't seem to read out and check the CRC-8, so you will not know if you have a transfer error. If you get an interrupt while communicating, one of your wait loops could take too long, resulting in either the DS18B20 or your side failing the difference between a zero and a one.

  • You are at gmt+1, me +2 :)

    I will follow your recommendation concerning unsigned integers. Most probably this issue caused me problems.

    "// Wait this long" comment is not mine. I found a delay function on the net and modified a bit. Comment comes from that paste :) Function was something like:

    void delay_ms(unsigned int msec)
    {
     T1TCR = 0x02; // Reset
     T1MCR = 0x07; // stop, reset and Interrupt
     T1PR  = 15000;
     T1MR0 = msec; // Wait this long
     T1TCR = 0x01; // Go
     while(!(T1IR & 1)); // Wait for int flag
     T1IR = 0x01; // Clear interrupt
    }
    


    Comments are very important. I sometimes forgot to modify or update. Due to its little code size, I thougt I understant the lines and functions (I have red also ds18b20 datasheet and grasped most parts) and left modification after finishing the code. You are right, if I request help from others, first I have to give descriptions, comments etc.

    For the version control, sometimes I did it in very primitive way (daily or after some succes I get compressed back up and name it in a descriptive way). For an hobbyist like me, I think it is acceptable :)

  • Yes, I'm at GMT+1 (Sweden).

    Don't do zip files. Hobbyist or professional doesn't much matter. The problems to solve is the same. Basically - what code constitutes a specific version? What was changed between two versions? What may be the reason that two versions behaves differently?

    There are many free solutions available. Why not try a CVSNT repository? Works fine on a Windows machine, and since the repository is just text files, a bad disk accident still makes it possible to extract information from whatever files or disk sectors that did survive.

  • Working with integer aritmetic is much faster than floating aritmetic, but it is difficult to handle especially if the result will be used in, let's say, logarithmic function.

    I have to study this integer calculation first on pencil-paper :)

    For disabling global interrupt, I need some time :) I haven't come to Interrupts chapter of "The Insider's Guide To The Philips ARM7-Based Microcontrollers" :) For CRC check, there are some examples, especially written for ds18b20, that I will implement in this code later (it will be second phase work).

  • For disabling global interrupt, I need some time :) I haven't come to Interrupts chapter of "The Insider's Guide To The Philips ARM7-Based Microcontrollers" :)

    void __asm __swi(12) disable_interrupts(void) ;
    void __asm __SWI_12                               (void)
    {
            MRS             R1, SPSR
    
            ORR             R1, R1, #0xC0 // disable IRQ and FIQ
    
            MSR             SPSR_c, R1
    
            BX LR
    }
    
    // writing to the CPSR register requires entering privileged mode
    void __asm __swi(13) enable_interrupts(void) ;
    void __asm __SWI_13                              (void)
    {
            MRS             R1, SPSR
    
            BIC             R1, R1, #0xC0 // enable IRQ and FIQ
    
            MSR             SPSR_c, R1
    
            BX LR
    }
    

    if you are using the RealView compiler, you can also use its intrinsic functions to do the same.

  •  float ds1820_read()
    {
     char busy=0,t2, t1, i;
     int  tt=0;
     float result;
     __SWI_12();// disables Global Interrupt
     i=onewire_reset();
     if(i==1) {
       print("*** Reset basarisiz ***");
       return (-273.15);
     }
     onewire_write(0xCC); // skip rom        write 1 byte
     onewire_write(0x44); // 44 ölçümü baslatir.
     while (busy == 0) busy = onewire_read();
     onewire_reset();
     onewire_write(0xCC);
     onewire_write(0xBE);
     t1 = onewire_read();
     t2 = onewire_read();
     __SWI_13();// enables Global Interrupt
     tt= ((int) t2<<8) | ((int)t1 & 0xFF);
     result = (float)tt / 16.0;  //defauld conf. 12 bit resolution
     return(result);
    }
    

    Dear Tamir, Is this a correct calling of the software interrupts you have given?

  • Dear Westermark,
    I have no previous CVS experience. I have just downloaded a free version, not yet installed. I will try. Thanks ... (PS:I am from Turkiye.)

  • No. Use them like normal functions/function pointers:

    disable_interrupts() ;
    

    Do note that you must update your SWI.s file to use SWI functions. You can always use the native RealView intrinsic functions

    void __disable_irq(void);
    void __enable_irq(void);
    void __disable_fiq(void);
    void __enable_fiq(void);
    

    instead. This exempts you from making any further changes other than to include a header (no SWI.s changes needed).

  • I tried this

     ...
    enable_interrupts() ;
    ...
    disable_interrupts() ;
    ...
    

    but compiler gave errors, saying undefined funtions enable..., disable... The code above with colored red function call was compiled and in the simulator called as ordinary function call. I know calling normal function is different than branching to an ISR by an interrupt source. AFAIK the latter changes the operation mode which may allow certain modifcation on the settings that are not allowed in user mode. Is this correct?

    I think I should copy a SWI.s file to working folder and include to the project :)

  • Note that your timing is critical while doing the individual operations, such as reset (to a lesser degree), and reading or writing individual bits. But the onewire interface allows you to pause the transfer between the individual bits.

    This allows you to only disable interrupts around each bit transfer, instead of having one huge (and very slow) section where interrupts are disabled for milliseconds.

    Too long sections with interrupts disabled means that serial communication and other activities that are interrupt-driven may fail. For serial communication, you may get overruns because you don't pick up received characters before new ones arrives. Even when the processor have a receive FIFO, you still have to service the UART regularly.

  • Dear Westermark,
    you are absolutely right. So I will transfer the disable and enable interrupts call instruction to bit writing or reading loops of write and read functions.