0

For a project I am connecting two MSP's (MSP430FR6989) with each other, one as a master (of which the code has been given and I cannot change a lot about it, so I cannot use SPI) and one as a slave. The slave one will just act as a memory extension to the master (who will write an address and data to the slave). There are many ways of "solving" this, however my hand was forced in how to do it.

The master will write an address to the slave, and he will also pull one pin high (doesn't do anything on the slave) and another low (will cause an interrupt on the slave). These pins are respectively 3.0 and 3.1. Depending on which pin is pulled low, the slave will either read the data from the master and store it in the address the master has given, or it will look at the address and write the data stored at this address to the master.

As you can imagine, a lot of timing problems occur when you just do this (data doesn't stay on the pins long enough, etc.). I tried to solve this by using the pin 3.2. The master will only read if that pin is pulled High(it will basically poll the entire time since the master need not do anything else in this time). The same thing happens (about ish) when writing. The master will push this pin Low again

The pieces for the code of the master are:

    void write(uint16_t address, uint8_t data){
    splitAndWriteAddress(address);  // splits up the address over the available pins in ports and writes it.
    P2DIR |= 0xFF;      // set dataIO in write mode
    P3OUT |= BIT1;      // deactivate read mode
    P3OUT &= ~BIT0;     // activate write mode
    P2OUT = data;       // write data
    while(!(P3IN & BIT2)){
        __no_operation();
    }
    P3OUT |= BIT0;      // deactivate write mode
    P3DIR |= BIT2;
    P3OUT &= ~BIT2;
    P3DIR &= ~BIT2;
    //P2DIR |= 0x00;      // set dataIO in read mode

}



    uint8_t read(uint16_t address){
    uint8_t data = 0x00;
    splitAndWriteAddress(address);
    P2DIR &= 0x00;      // set dataIO in read mode
    P3OUT |= BIT0;      // deactivate write mode
    P3OUT &= ~BIT1;     // activate read mode
    while(!(P3IN & BIT2)){
        __no_operation();
    }
    data = P2IN;
    P3OUT |= BIT1;      // deactivate read mode
    P3DIR |= BIT2;
    P3OUT &= ~BIT2;
    P3DIR &= ~BIT2;
    return data;
}

And for the slave I have made an interrupt:

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT3_VECTOR
__interrupt void Port_3(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT3_VECTOR))) Port_3 (void)
#else
#error Compiler not supported!
#endif
{
    /*
     * 4 usable RAM sections:
     * 1. D --> 1800h 'till 187Fh
     * 2. C --> 1880h 'till 18FFh
     * 3. B --> 1900h 'till 187Fh
     * 4. A --> 1980h 'till 19FFh
     */
    uint16_t volatile * address = (uint16_t *) getAddress(); // gets the address from the ports
    P3DIR |= BIT2;


        if(P3IFG & BIT0){
            P2DIR &= 0x00;  // put in read mode
            *address = P2IN;
            P3OUT |= BIT2;
        }
        //WRITE
        if(P3IFG & BIT1){ //could be an else
            P2DIR |= 0xFF;  // put in write mode
            P2OUT = *address;
            P3OUT |= BIT2;
        }

    P3DIR &= ~BIT2;

    P3IFG=0; // set all flags to 0
}

When debugging, everything works fine (I test using an UART connection) , but when running as normal (in release mode), it does not anymore (the data and address are all given through correctly). This makes me think that it is still a timing error, however I don't know how and why.

I was also thinking that I should be able to do it without using that port 3.2, but I have not tried it yet, because I think there will also be some major timing issues there which I don't know how to solve right now.

If more code is needed please ask, but those are just about the only ones that matter I think.

With kind regards.

DYD35
  • 121
  • 1
  • 7
  • 1
    “It does not [work] anymore” - explain in detail, with specifics, exactly what doesn’t work. – DisappointedByUnaccountableMod Aug 14 '20 at 21:16
  • 1
    How do you avoid that both P2DIRs are configured as outputs at the same time? As far as I can see, not at all. And how long does P3.2 stay high? – CL. Aug 14 '20 at 21:21
  • Yeah definitely synchronisation gaps in the code – DisappointedByUnaccountableMod Aug 14 '20 at 21:22
  • @barny when debugging I can go line by line and see the memory and registers. There everything is fine. When I just run the code as normal, I get no data or jibberish when I read again as the master (after written to the slave obviously). I am going to do a UART on the slave as well to see if anything there is "wrong" (I mean if there is no data) – DYD35 Aug 14 '20 at 21:29
  • @CL. P3.2 stays High untill the master pulls it Low again. In the slave interrupt you can see that it is pulled High and (almost) immediatly the DIR of this pin is changed to read so that the master can pull it low again. The P2DIR I also have trouble with, I am thinking that I should put it in Read (0x00) in the slave Write part (of the interrupt) immediatly after writing on it as to avoid this problem. However, if I do that I stumble into the problem that the lines could be overwritten by something else (e.g. induction although improbable), thus corrupting the data. – DYD35 Aug 14 '20 at 21:32
  • @barny I am thinking the same, but I fail to spot where (both MCU's are on the same CLK freq.), and after a week of testing I decided to ask here if someone would have an idea to tackle this problem. – DYD35 Aug 14 '20 at 21:34
  • Your code on both sides (local/remote) needs to initialise the pins permanently to either input or output except the ‘data’ P2 which must default to input and only be made output briefly by whichever side is outputting. If outputting, the side must actually output data on P2 before triggering/acknowledging, and only remove that data once the trigger/acknowledge cycle is complete. I suggest you have the local output a ‘trigger (default 0)’ a R/~W line, and the remote output an acknowledge (default 0) - that way you only need a single interrupt input on the remote. – DisappointedByUnaccountableMod Aug 14 '20 at 21:52
  • 2
    The sequence for read is local sets R/~W to 1 and sets trigger to 1, waits for ack to go to 1, reads data from P2, saves it, sets trigger to 0 and waits for ack to go to 0. At the remote when trigger goes to 1 and R/~W is 1, it reads the address, Sets P2 to output, outputs data on P2, sets ack to 1, waits for trigger to go to 0 and sets P to input, sets ack to 0. – DisappointedByUnaccountableMod Aug 14 '20 at 21:57
  • 2
    The sequence for write is: local outputs data on P2, sets R/~W to 0 and sets trigger to 1, then waits for ack to go high when it sets P2 to input and sets trigger to 0 and waits for ack to go to 0. On remote when trigger goes to 1 and R/~W is 0, it reads P2, writes the data into RAM, sets ack to 1 and waits for Trigger to go to 0 then sets ack to 0 – DisappointedByUnaccountableMod Aug 14 '20 at 22:00
  • @barny that is a smart solution! I was given the code of the master so I was stuck in the mindset of it. However, using the CTRL pins for different purposes makes is easier indeed!! Thank you! I will try this asap and come back with a result. In the meantime, is the trigger really necesarry though? I could make an interrupt whenever the R/W line goes either up or down, which would free up one line, however it will make for less safety. – DYD35 Aug 14 '20 at 22:07
  • Thanks, I’m not really sure how else you could safely do synchronous data transfer like this. The above sequences could also work with polling by the remote rather than interrupt, as long as both sides are designed to handle delays of polling - the remote needs to be able to respond quickly. – DisappointedByUnaccountableMod Aug 14 '20 at 22:14
  • No don’t be tempted to use the R/~W line to trigger. At least get what I’ve suggested working - you can always develop from a working solution. – DisappointedByUnaccountableMod Aug 15 '20 at 20:52
  • It worked using the trigger line. Thanks for the help. – DYD35 Aug 16 '20 at 15:11

0 Answers0