Adam Crowder

Isolated problem with MCF54417 1-Wire Module (documentation)

Discussion created by Adam Crowder on Nov 18, 2015
Latest reply on Nov 19, 2015 by TomE

Implementing communications to a Dallas 1-wire temperature sensor in my OS in the MCF54417 CPU, I discovered a bug.

 

I expected this to be the easiest 1-wire implementation ever, since I'd bit-banged all previous implementations!  Tests run in the boot-loader code proved out the hardware by correctly measuring the temperature from the device.

 

However, when I tried to implement the exact same subroutine in the OS code, it failed in strange ways!

 

Section 36.4.1.3 ("Byte Transfers") suggests the following procedure:

 

1. Write 0xFF to OW_TXRX (connected to the transmit buffer).

2. Wait for the receive-buffer-full DMA request or interrupt (or poll OW_ISR[RBF] directly if the

interrupt is disabled). During this time, the hardware is writing ones on the bus while sampling the

wired-AND of the data from the device. The read data is shifted into the receive shift register.

When a byte is collected in the receive shift register, the data is transferred to the receive buffer,

and the RBF flag sets.

3. Read from OW_TXRX (connected to the receive buffer) upon receiving the RBF interrupt or DMA

request.

In my code I did not implement interrupts, since this would be used very seldom.  Instead I wrote to OW_TXRX and then polled OW_ISR[RBF] in a tight loop.  Lengthy testing eventually led me to realize:

 

When the CPU sets the OW_ISR[RBF] bit, it is NOT READY for the OW_TXRX register to be read!

 

byte OW_TxRx( byte TxByte) {     byte RetVal;     if( (MCF_OW_ISR & MCF_OW_ISR_RBF)) { // should NOT be set already!         (void) MCF_OW_TXRX; // Dummy read to clear         #ifdef DEBUG_OW             iprintf( "OW_TxRx() had to clear RBF on start\n");         #endif     }                  MCF_OW_TXRX = TxByte;          while( !(MCF_OW_ISR & MCF_OW_ISR_RBF))         ; //           asm( "nop"); // A minimum of 3 NOPs are required to make this work     asm( "nop"); // More may be needed at higher temperatures..????     asm( "nop");     asm( "nop");     asm( "nop");     asm( "nop");     asm( "nop");     asm( "nop");     asm( "nop");          RetVal = MCF_OW_TXRX; // Reading this register clears the RBF flag          return RetVal; } 

 

What I saw was that every OTHER call to this function would find the OW_ISR[RBF] bit already set, and the data I'd have read immediately before this bit was erroneously set would have been a duplicate of the time before.

 

Adding the "nop" instructions was the "fix" for the hardware bug.  It seems clear to me that the hardware is FIRST setting the RBF bit and THEN placing the data into the TXRX register.  I suspect that if I'd implemented an interrupt service function, that the latency of servicing the interrupt would have masked this bug (and may be how Freescale managed to convince themselves this was working).

Outcomes