Messaging between multiple Maple Mini clones

What are you developing?
joevpt
Posts: 12
Joined: Sat Aug 27, 2016 6:38 pm

Re: Messaging between multiple Maple Mini clones

Post by joevpt » Sun Aug 28, 2016 3:14 pm

RogerClark wrote:If you get this working, could you let us know and post a small schematic diagram

Thanks

Roger
Having a problem with the units under test so removing the diagram until I get to the bottom of it. I Don't want anyone frying their boards because of my mistake !!
Last edited by joevpt on Tue Aug 30, 2016 11:22 am, edited 3 times in total.

simonf
Posts: 180
Joined: Sun Jul 26, 2015 4:03 pm

Re: Messaging between multiple Maple Mini clones

Post by simonf » Sun Aug 28, 2016 4:50 pm

rreignier wrote:Hi,
What you trying to do seems to be what ST call Multiprocessor communication as explained at paragraph 27.3.6 in the F103 Reference Manual (RM0008).
I have never tried that but just wanted to let you know that is is documented by ST.

Without the mute PIn. It depends on the amount of data / the chance of collision whether you need the mute. Effectively you should not transmit if there are character(s) in the rx buffer ie there is an inward packet. If at the end of the tx the message in you rx buffer is the same you know the packet was successfully sent (Not 100% certain it would have been recieved). The recipient then sends either a reply or an acknowledge.

Also I have not done this but it should be possible to emulate the mute pin by setting a "BusBusy" flag when the rx pin goes low. This would get reset when complete message is read from the buffer and there are no longer any characters in the buffer.
I am not certain if you can attachInterupt to the RXpin but I can't see why not, if not you would need to wire the RX to another pin and use that. In the event you still only need one wire for your bus.

The other advantage to this approach is 3.3v devices and 5v devices can talk to each other the pull up needs to go to 3.3v as 3.3v is usually enough to be considered HIGH on most 5V systems. For example a 5V ATmega32U4 needs the pin to be over 1.9v to be considered high.

My data packet consists of a command byte and an operand. I often use upper and lower case letters to signify commands and replies. I usually have some kind of PING command to test the bus and that the other devices are live. On start up one device would send say 'p' as data meaning ping then the receiver would reply 'P' (Acknowledging Ping). Again if device one say wanted to read the second temp sensor from device "3" then. The Request data would look like 't2' the reply would be 'T2<data>' .

Something like this

Code: Select all

From - To - Length -Data -Checksum
01x - 03x - 01x - "p" - <checksum>  <Ping Recipient
03x - 01x - 01x - "P" - <checksum>  <Ping Reply
01x - 03x - 02x - "t2" - <checksum>  <Temp Request
03x - 01x - 06x - "T2100C" - <checksum> <Temp Reply

joevpt
Posts: 12
Joined: Sat Aug 27, 2016 6:38 pm

Re: Messaging between multiple Maple Mini clones

Post by joevpt » Tue Sep 06, 2016 12:34 pm

Finally got around to this yesterday, and have it working now in a master/slave configuration. I tested it using a teensy 3.2 as the master device and multiple maple mini clones as the slave devices. For the master transit pin, no special conditioning is needed, but I put a pullup resistor at each slave receive pin. In my case with three slaves, I used 80k resistors because I had them.

For the slave transmit, I used a small diode at the transmit pin before joining the master receive bus.

To test, I've had a small program send a string every two seconds for the past 24 hours, and have each slave acknowledge that they received it. To avoid collisions on the bus I used 100ms increments of delay on each slave (first slave 100ms, second slave 200ms, third slave 300ms) before sending the ack.

The basic circuit is shown below. I now need to write a simple protocol for my needs. My intention is to use one byte address, two bytes message length, the message, and a CRC. I intend have every single address transmission be acknowledged. Every broadcast will not be acknowledged. In this way it is a simple matter to mediate who has control of the bus.

Just to be clear, I am using a TX/RX pair of pins for this (because I cannot get the I2C slave to work). In my test, I used TX1/RX1 on both the teensy and the maple mini clones as it allowed me to use the USB serial monitor to see what was going on.
cct.png
cct.png (4.68 KiB) Viewed 554 times

simonf
Posts: 180
Joined: Sun Jul 26, 2015 4:03 pm

Re: Messaging between multiple Maple Mini clones

Post by simonf » Tue Sep 06, 2016 2:05 pm

joevpt wrote:Finally got around to this yesterday, and have it working now in a master/slave configuration. I tested it using a teensy 3.2 as the master device and multiple maple mini clones as the slave devices. For the master transit pin, no special conditioning is needed, but I put a pullup resistor at each slave receive pin. In my case with three slaves, I used 80k resistors because I had them.
Hi, when i described the connection I actually used a single bus you can common the TX and RX. Albeit the TX are connected via a diode. Think 10 Base-T on a small scale. You can detect collisions by checking you receive the message you sent. Also the bus is "Busy" soon as the RX pin goes low and remains "Busy" until a whole message is received. The only disadvantage of this is the system becomes simplex not duplex.

Also using it this way any device can talk to any other device no need for Master/Slave no need for an arbitrator.
Last edited by simonf on Tue Sep 06, 2016 6:12 pm, edited 1 time in total.

madias
Posts: 813
Joined: Mon Apr 27, 2015 11:26 am
Location: Vienna, Austria

Re: Messaging between multiple Maple Mini clones

Post by madias » Tue Sep 06, 2016 2:30 pm

joevpt wrote: Just to be clear, I am using a TX/RX pair of pins for this (because I cannot get the I2C slave to work).
I think nobody got I2C-slave to work on STM32duino --> http://www.stm32duino.com/viewtopic.php?t=1236

fredbox
Posts: 95
Joined: Tue Jul 07, 2015 4:44 pm

Re: Messaging between multiple Maple Mini clones

Post by fredbox » Tue Sep 06, 2016 5:06 pm

I now need to write a simple protocol for my needs. My intention is to use one byte address, two bytes message length, the message, and a CRC. I intend have every single address transmission be acknowledged. Every broadcast will not be acknowledged. In this way it is a simple matter to mediate who has control of the bus.
My day job involves communications between industrial devices. What you are describing is Modbus/RTU, probably using function code 03 or 04. The protocol is serial, allows up to 247 device addresses and has a crc at the end. See SimplyModbus.ca for information on the protocol.

User avatar
Slammer
Posts: 255
Joined: Tue Mar 01, 2016 10:35 pm
Location: Athens, Greece

Re: Messaging between multiple Maple Mini clones

Post by Slammer » Wed Sep 07, 2016 2:47 pm

You dont have to reinvent the wheel, modbus is very simple and common master-slave protocol.
Here is a very nice implementation of modbus : http://libmodbus.org/
you can also check the arduino implementation of libmodbus here : http://libmodbus.org/2011/libmodbus-for-arduino-almost/ ( I have used this implementation many times with AVRs)

User avatar
RogerClark
Posts: 7433
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Messaging between multiple Maple Mini clones

Post by RogerClark » Wed Sep 07, 2016 9:55 pm

Slammer

Thanks for posting those modbus libs links.

I wrote a minimal modbus implementation with just a few functions e.g. writeRegister writeCoil etc, and it was very simple.

The only difficult bit is the custom CRC and there was example code on the web

User avatar
Slammer
Posts: 255
Joined: Tue Mar 01, 2016 10:35 pm
Location: Athens, Greece

Re: Messaging between multiple Maple Mini clones

Post by Slammer » Thu Sep 08, 2016 1:00 am

There are two ways to implement CRC calculation. The first is to make all calculations by code and the second way is to use a lookup table.
In 8051/AVR world the lookup table method is better and faster but requires some code memory more (512 bytes for tables), in ARM world the speed is not an issue and the computational method is more elegant.

Here is my code for lookup table method (using the PROGMEM directive of gcc-avr for storing tables in FLASH)

Code: Select all

uint8_t CRCHi[]  PROGMEM = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
uint8_t	CRCLo[] PROGMEM = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};

/*---------------------------------------------------------------------------*/
/**
  @brief	calculate the CRC16 value of the input data
  @param	buf		input data
  @param	len		length of the input data
  @return	CRC16 value of the input data
 */
/*---------------------------------------------------------------------------*/

uint16_t	CRC16( uint8_t *buf, uint8_t len)
{
	uint8_t	hi=0xFF;
	uint8_t	lo=0xFF;
	uint16_t 	index;
	while ( len-- ) {
		index = lo ^ (uint8_t)*buf++;
		lo = hi ^ pgm_read_byte(&CRCHi[index]);
		hi = pgm_read_byte(&CRCLo[index]);
	}

	index = lo << 8;
	index |= hi;
	return(index);
}
And here is the computational method :

Code: Select all

uint16_t CRC16(uint8_t *req, uint8_t req_length)
{
    uint8_t j;
    uint16_t crc;

    crc = 0xFFFF;
    while (req_length--) {
	crc = crc ^ *req++;
	for (j=0; j < 8; j++) {
	    if (crc & 0x0001)
		crc = (crc >> 1) ^ 0xA001;
	    else
		crc = crc >> 1;
	}
    }

    return (crc << 8  | crc >> 8);
}

User avatar
RogerClark
Posts: 7433
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Messaging between multiple Maple Mini clones

Post by RogerClark » Thu Sep 08, 2016 1:15 am

I think I used the computational method, but both are valid. The Modbus data I was so small that the CRC calculation time was insignificant

Post Reply