[closed:right code inside]Always set the 9th bit automatically in MPCM on ATTINY814

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I need to connect many sensors to master MCU, so MPCM one-wire USART is my choice.

There is a bug , I can't find out the reason: the 9th bit is set every time.

Anyone can find the bug in the code?

 

init:

void USART0_oneWireInit(void) {
    
    PORTB.DIRCLR = PIN2_bm; //default USART.TxD = PB2
    USART0.BAUD = (uint16_t)USART0_BAUD_RATE(9600);
    
    USART0.CTRLA |= (USART_LBME_bm | USART_RXCIE_bm);
    
    USART0.CTRLB = 1 << USART_MPCM_bp   // Multi-processor Communication Mode: enabled
        | 1 << USART_ODME_bp            // Open Drain Mode Enable: disabled
        | USART_RXMODE_CLK2X_gc         // CLK2x mode
        | 1 << USART_SFDEN_bp           // Start Frame Detection Enable: enabled
        | 1 << USART_TXEN_bp            // Transmitter Enable: enabled
        | 1 << USART_RXEN_bp;           // Reciever enable: enabled

    USART0.CTRLC =
          USART_CHSIZE_9BITH_gc         // Character size: 9 bit read high byte first
        | USART_PMODE_EVEN_gc ;         // Even Parity

}

RXC interrupt handler:

 

ISR(USART0_RXC_vect){

    uint8_t rxDataH = USART0.RXDATAH;
    uint8_t rxDataL = USART0.RXDATAL;
    
    switch(uartStatus){
        case uartSending:
            if(rxDataL == charToSend){
                sendingStatus = uartSendOK;
            }else{
                sendingStatus = uartSendCONFLICT;
            }
            return;
        case uartReceiveIdle: //address frame 
            //uartRcvPush(rxDataL,rxDataH); return;
            
            if( !(rxDataH & 0x06) && (rxDataH & 1)){ //FERR=0 PERR=0 adress frame
                if((rxDataL == sensorID)||(rxDataL == 0xFF)){
                    DISABLE_MPCM;
                    uartStatus = uartReceiving;
                    uartRcvPush(rxDataL,true);
                    return;
                }
            }
            break;
        case uartReceiving: //data frame process
            //uartRcvPush(rxDataL,rxDataH); return;
            
            if(!(rxDataH & 0x07)){ //FERR==0 and PERR==0 and 9th bit==0
                uartRcvPush(rxDataL,false);
                return;  
            }
            
            if(rxDataH & 0x06) 
                return; //FERR=1 or PERR=1 ,just throw it
            else
                if((rxDataH & 1)){ //FERR=0 PERR=0 adress frame
                    if((rxDataL == sensorID)||(rxDataL == 0xFF)){ //continue to send
                        uartRcvPush(rxDataL,true);
                    }else{ //send to other
                        ENABLE_MPCM;
                        uartStatus = uartReceiveIdle;
                    }    
                }
            return;
        default:return;
    }

      
}

send code:

 

uartSendStatus_t USART0_oneWireSend(void){
    uartStatus = uartSending;
    
    PORTB.DIRSET = PIN2_bm;           // pb2 pin must be output to transmit
    
    for(uint8_t i = 0; i <= uartDataIdx; i++){
        charToSend = uartDataToSend[i].data;
        while (!(USART0.STATUS & USART_DREIF_bm)){;}  
        if(uartDataToSend[i].addressBit)
            USART0.TXDATAH |= 1;

       else
            USART0.TXDATAH &= 0xFE;
        USART0.TXDATAL = charToSend;

 

        sendingStatus = uartSendSENDING;
        while(sendingStatus == uartSendSENDING){ //need to check if timeout
        }

        if(sendingStatus != uartSendOK){
            break;
        }
        
    }
    
    PORTB.DIRCLR = PIN2_bm;
    uartStatus = uartReceiveIdle;
    
    return sendingStatus;
}

In the send function, I set the 9th bit for every byte, only 1st address byte was set with 1, all other byte is 0.

But, with loop back check, what RxD received is always RXDATAH = 0x81 & RXDATAL = what sent on TxD.

And I checked the other receiver(sensors), what they received is same as upper.

 

That means the 9th bit was set to 1 before sent out.

Where is the bug? 

 

 

This topic has a solution.
Last Edited: Tue. Aug 27, 2019 - 03:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A strange thing :

 

       if(uartDataToSend[i].addressBit)
            USART0.TXDATAH |= 1;

       else
            USART0.TXDATAH &= 0xFE;

 

Error will triggered if replaced "USART0.TXDATAH |= 1;" with "USART0.TXDATAH = 1;".

This happened to anyone else?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you checked the Errata of this tiny814:

 

http://ww1.microchip.com/downloa...

 

check USART section.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moe : 

Checked, no related information.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How can you expect us to solve, when there are mystery macros?

Xiao wrote:
ENABLE_MPCM;
Xiao wrote:
DISABLE_MPCM;

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

amaizing !

 

it failed to send every time if set like this: 

        if(uartDataToSend[i].addressBit)
            USART0.TXDATAH |= 0x01;
        else                    
            USART0.TXDATAH &= 0x00; 

or

USART0.TXDATAH = uartDataToSend[i].addressBit;

 

sending will be OK like this:

 

        if(uartDataToSend[i].addressBit)
            USART0.TXDATAH |= 0x01;
        //else                    
           // USART0.TXDATAH &= 0x00; 

but you will receive 9th bit as 1 everytime, that is my bug comes from : maybe I write the code like this before : 

 

USART0.TXDATAH |= uartDataToSend[i].addressBit;

That was wrong, it can't clear the 9th bit.

 

but, new problem raised: how to clear it?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#define  DISABLE_MPCM   { USART0.CTRLB &= ~(1 << USART_MPCM_bp); }
#define  ENABLE_MPCM    { USART0.CTRLB |= (1 << USART_MPCM_bp); }

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Remember that &= 0 clears all bits of the destination.  Show the generated code for your sequence.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Debug for a while, learning something,share with newbie :)

 

I don't understand the theory so clearly.

 

After traced the execution with ATMEL-ICE, codes listed below are right, the content of TXDATAH changed indeed.

 

  if(uartDataToSend[i].addressBit)
            USART0.TXDATAH |= 0x01;
        else                    
            USART0.TXDATAH &= 0x00; 

or

 

  USART0.TXDATAH &= uartDataToSend[i].addressBit;

  

 

This is the cause of chaoes:

For the sender configured as MPCM + Loopback too,

RxD will receive what sent on TxD when 9th bit ==1, (remember that the sender is in MPCM too: receive only address frame)

and RXC interrupt will not triggered while 9th bit ==0, (it is data frame, not address frame) , that means it will not receive what sent on TxD.

 

So, the conclusion: 

Sender configured as MPCM + LoopBack will only received the address frame only in it's RxD(receiver).

 

So,it will make troubles to conflict check through loopback receiving.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

USART0.TXDATAH |= 1;

you have 1 bit in that register- bit0, there is nothing else there so just set it-

 

USART0.TXDATAH = uartDataToSend[i].addressBit; //assuming addressBit is 1 or 0

 

 

Datasheet on MPCM bit-

Writing a ‘1’ to this bit enables the Multi-Processor Communication mode: the USART receiver ignores all
the incoming frames that do not contain address information. 

So if the receiver is ignoring everything other than address frames (bit 9 set) when MPCM is on, then you will not see any rx data. I cannot sort out when you have MPCM mode on or off, but if you are sending data frames with MPCM mode on, then rx will not see them. You initially have it on, so if sending out an address frame you will see the address frame but it will not match the senders address, so MPCM mode remains on and rx ignores the data frames.

 

I know nothing of MPCM mode, but if you want to monitor all outgoing tx in one-wire mode, then I would think the MPCM mode would have to be off. So at least turn it off when transmitting so you can monitor for collisions. When back to receive mode, turn it on.

 

I'm not sure why you are messing with setting pin direction, when you had another thread where I showed that the usart takes care of it all in open-drain mode, except for the pullup.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

go on.

 

curtvm is right.

Just disable the MPCM before transferring, and enabled after that.

 

And not end yet for me.

Though no conflict happed in sender side, the data received in other sensor is not always right.

Need some checksum method.

 

the function to send data works well now:

 

uartSendStatus_t USART0_oneWireSend(void){
    uint16_t timeoutCycles;
    
    uartStatus = uartSending;
    PORTB.DIRSET = PIN2_bm;         // pb2 pin must be output to transmit
    
    DISABLE_MPCM; 
    
    for(uint8_t i = 0; i <= uartDataIdx; i++){
        charToSend = uartDataToSend[i].data;

        while (!(USART0.STATUS & USART_DREIF_bm)){;}  
        USART0.TXDATAH = uartDataToSend[i].addressBit;
        USART0.TXDATAL = charToSend;
        
        timeoutCycles = 64000; //4*16000/16=4ms
        sendingStatus = uartSendSENDING;
        while(sendingStatus == uartSendSENDING){ //need to check if timeout
            if(--timeoutCycles==0){
                USART0.CTRLB &= ~USART_RXEN_bm;
                USART0.CTRLB &= ~USART_TXEN_bm;
                USART0.CTRLA &= ~USART_RXCIE_bm;
                USART0.CTRLA |= USART_RXCIE_bm;
                USART0.CTRLB |= USART_RXEN_bm;
                USART0.CTRLB |= USART_TXEN_bm;
                break;
            }    
        }
        if(sendingStatus != uartSendOK){
            break;
        }
        
    }
    
    PORTB.DIRCLR = PIN2_bm;
    uartStatus = uartReceiveIdle;
    ENABLE_MPCM;
    
    return sendingStatus;
}
 

 

 

the recover code not test(actually don't know how to :)) , just for reference.

Thank you all. 

Last Edited: Tue. Aug 27, 2019 - 03:22 PM