Difference between Signal based routing and PDU based routing in AUTOSAR - serial-port

Trying to understand difference in performance of signal based routing and PDU based routing in AUTOSAR.
As per my understanding,
Signal based routing -> The signal need to be converted to I-PDU and routed
PDU based routing -> The PDU directly routed
What is the difference in performance between these two.Because anyway routing is handled as PDU.
Some note could see that signal based routing having low latency. Why so? Whether signal based routing is overhead or not?

If my understanding is correct, there is a huge difference between PDU-based routing and signal-based routing. The PDU-based should be much faster.
Signal based routing -> The signal need to be converted to I-PDU and routed
PDU based routing -> The PDU directly routed
Seems pretty correct to me, so let's check an example with a CAN FD frame with several PDUs.
Byte 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
PDU [-------PDU_1------] [--PDU_2--]
Signal II II II
Signal_1 Signal_2 Signal_3
4 bits 3 bits 1 bit
If the PDU_1 is routed using PDU-based routing, from the software perspective, it's just a matter of copying the 7 bytes of PDU_1 to another PDU with the same structure. No need to highlight how fast it is to copy a few bytes from a memory location to another memory location. You can find this case when you have a gateway in Automotive translating PDUs from CAN FD to Flexray and back.
If we use signal-based routing, it's another topic, much more complicated if we consider the software implementation. The software will need to extract the value of Signal_1 and Signal_2 from the the byte fields, then use the factor and offset to determine its physical value with floating points numbers and then convert back to the destination signal which might not have the exact same factor or offset. There are much more calculations involved and this has a strong impact on the performances if the number of signal is important. If you need this, you probably want a MCU with a floating point unit.
static uint32_t GW_GetSignal_1 (uint8_t *Data)
{
uint32_t Byte_0 = Data[0];
uint32_t Bytes = (Byte_0 >> 3);
uint32_t SignalValue = (Bytes & 0xF); /* 0000.1111 */
return SignalValue;
}
static uint32_t GW_GetSignal_2 (uint8_t *Data)
{
uint32_t Byte_0 = Data[0];
uint32_t Bytes = (Byte_0 >> 0);
uint32_t SignalValue = (Bytes & 0x7); /* 0000.0111 */
return SignalValue;
}
static float Raw32ToPhysical (uint32_t RawValue, float Factor, float Offset)
{
float PhysicalValue = ((float)RawValue) * Factor + Offset;
return PhysicalValue;
}

Related

Serial point to point protocol but with 8 bytes instead of 16

I was looking at answers in Simple serial point-to-point communication protocol and it doesn't help me enough with my issue. I am also trying to communicate data between a computer and an 8-bit microcontroller at first, then eventually I want to communicate the one microcontroller to about 40 others via wireless radio modules. Basically one is designated as a master and the rest are slaves.
speed is an issue
The issue at hand is speed. because communication of every packet needs to be done at least 4x a second back and forth between the master and each slave.
Let's assume baud rate for data is 9600bps. That's 960 bytes a second.
If I used 16-byte packets then: 40 (slaves) times 16 (bytes) times 2 (ways) = 640. Divide that into 960 and that would mean well more than 1/2 a second. Not good.
If I used 8-byte packets then: 40 (slaves) times 8 (bytes) times 2 (ways) = 320. Divide that into 960 and that would mean 1/3 second. It's so-so.
But the thing is I need to watch my baud because too high of baud might mean missed data at larger distances, but you can see the speed difference between an 8 and 16 byte packet.
packet format idea
In my design, I may have a need to transmit a number in the low millions so that will use 24-bits which fits in my idea. But here's my initial idea:
Byte 1: Recipient address 0-255
Byte 2: Sender address 0-255
Byte 3: Command
Byte 4-6: Data
Byte 7-8: 16-bit fletcher checksum of above data
I don't mind if the above format is adjusted, just as long as I have at least 6 bits to identify the sender and receiver (since I'll only deal with 40 units), and the data with command included should be at least 4 bytes total.
How should I modify my data packet idea so that even the device that just turned on in the middle of reception can be in sync with the next set of data? Is there a way without stripping a bit from each data byte?
Rely on the check sum! My packet would consists of:
Recipient's address (0..40) XORed with 0x55
Sender's address (0..40) XORed with 0xAA
Command Byte
Data Byte 0
Data Byte 1
Data Byte 2
CRC8 sum, as suggested by Vroomfondel
Every receiver should have a sliding window of the last seven received bytes. When a byte was shifted in, that window should checked if it is valid:
Are the two addresses in the valid range?
Is it a valid command?
Is the CRC correct?
Especially the last one should safely reject packets on which the receiver hopped on off-sync.
If you have less than 32 command codes, you may go down to six bytes per packet: 40[Senders] times 40[Receivers] times 32[Commands] evaluates to 51200, which would fit into 16 bits instead of 24.
Don't forget to turn off the parity bit!
Update 2017-12-09: Here a receiving function:
typedef uint8_t U8;
void ByteReceived(U8 Byte)
{
static U8 Buf[7]; //Bytes received so far
static U8 BufBC=0;
Buf[BufBC++] = Byte;
if (BufBC<7) return; //Msg incomplete
/*** Seven Byte Message received ***/
//Check Addresses
U8 Adr;
Adr = Buf[0] ^ 0x55; if (Adr >= 40) goto Fail;
Adr = Buf[1] ^ 0xAA; if (Adr >= 40) goto Fail;
if (Buf[2] > ???) goto Fail; //Check Cmd
if (CalcCRC8(Buf, 6) != Buf[6]) goto Fail;
Evaluate(...);
BufBC=0; //empty Buf[]
return;
Fail:
//Seven Byte Msg invalid -> chop off first byte, could use memmove()
Buf[0] = Buf[1];
Buf[1] = Buf[2];
Buf[2] = Buf[3];
Buf[3] = Buf[4];
Buf[4] = Buf[5];
Buf[5] = Buf[6];
BufBC = 6;
}

how those bit-wise operation work and why wouldn't it use little/small endian instead

i found those at arduino.h library, and was confused about the lowbyte macro
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
at lowByte : wouldn't the conversion from WORD to uint8_t just take the low byte anyway? i know they w & 0x00ff to get the low byte but wouldn't the casting just take the low byte ?
at both the low/high : why wouldn't they use little endians, and read with size/offset
i.e. if the w is 0x12345678, high is 0x1234, low is 0x5678, they write it to memory as 78 56 34 12 at say offset x
to read the w, you read to size of word at location x
to read the high, you read byte/uint8_t at location x
to read the low, you read byte/uint8_t at location x + 2
at lowByte : wouldn't the conversion from WORD to uint8_t just take the low byte anyway? i know they w & 0x00ff to get the low byte but wouldn't the casting just take the low byte ?
Yes. Some people like to be extra explicit in their code anyway, but you are right.
at both the low/high : why wouldn't they use little endians, and read with size/offset
I don't know what that means, "use little endians".
But simply aliasing a WORD as a uint8_t and using pointer arithmetic to "move around" the original object generally has undefined behaviour. You can't alias objects like that. I know your teacher probably said you can because it's all just bits in memory, but your teacher was wrong; C and C++ are abstractions over computer code, and have rules of their own.
Bit-shifting is the conventional way to achieve this.
In the case of lowByte, yes the cast to uint8_t is equivalent to (w) & 0xff).
Regarding "using little endians", you don't want to access individual bytes of the value because you don't necessarily know whether your system is using big endian or little endian.
For example:
uint16_t n = 0x1234;
char *p = (char *)&n;
printf("0x%02x 0x%02x", p[0], p[1]);
If you ran this code on a little endian machine it would output:
0x34 0x12
But if you ran it on a big endian machine you would instead get:
0x12 0x34
By using shifts and bitwise operators you operate on the value which must be the same on all implementations instead of the representation of the value which may differ.
So don't operate on individual bytes unless you have a very specific reason to.

Difference between uint8_t* vs uint8_t

What is the difference/use for these 2 types? I have a basic understanding regarding pointers but I just can't wrap my head around this.
uint8_t* address_at_eeprom_location = (uint8_t*)10;
This line found in an Arduino example makes me feel so dumb. :)
So basically this is a double pointer?
The uint_t is the unsigned integer, this is the data stored directly in the memory. The uint_t * is the pointer to the memory in which the number is stored. The (uint_t*) is cast of the 10 - (literal which is translated to a number in the memory so the binary representation of the number ten) to the pointer type. This will create the storage to store the 10, and than will use its address and store it in the address_at_eeprom_location variable.
uint8_t is an unsigned 8 bit integer
uint8_t* is a pointer to an 8 bit integer in ram
(uint8_t*)10 is a pointer to an uint8_t at the address 10 in the ram
So basically this line saves the address of the location for an uint_8 in address_at_eeprom_location by setting it to 10. Most likely later in the code this address is used to write/read an actual uint8_t value to/from there.
Instead of a single value this can also be used as an starting point for an array later in the code:
uint8_t x = address_at_eeprom_location[3]
This would read the 3rd uint8_t starting from address 10 (so at address 13) in ram into the variable x

How to calculate a 256-modulo checksum on arduino

I am writing a computer program which utilizes input from some equipment which I seldom have availible in my office. In order to develop and test this program I am trying to use an Arduino board to simulate the communication from the actual equipment. To this effect I create datapackets on the Arduino and send them to my computeer over the serial port. The packets are formated as a header and a hexidecimal integer, representing some sensor data.
The header is supposed to contain a checksum (2's complement 256-modulo). I am however not sure how to calculate it. In the datasheet of the equipment (which communication I try to simulate), it is stated that I should first compute the sum all bytes in the packet, and then take the 256-modulo of the sum and perform a 8-bit two's complement on the result.
However, as I am a newbie to bits, bytes and serial communication, I do not understand the following:
1) Lets say that I want to send the value 5500 as two bytes (high byte and low byte). Then the high-byte is '15' and the low-byte is '7c' in hexidecimal encoding, which corresponds to 21 and 124 in decimal values. Do I then add the contributions 21 and 124 to the checksum before taking the 256-modulo, or do I have to do some bit-magic beforehand?
2) How do I perform a two's compliment?
Here is a code which should illustrate how I think. The idea is to send a packet with a header containing a byte which states the length of the packet, a byte which states the type of the packet, and a byte for the checksum. Then a two-byte integer value representing some sensor value is devided into a high-byte and a low-byte, and transmitted low-byte first.
int intVal;
byte Len = 5;
byte checksum;
byte Type = 2;
byte intValHi;
byte intValLo;
void setup(){
Serial.begin(9600);
}
void loop(){
intVal = 5500; //assume that this is a sensor value
intValHi = highByte(intVal);
intValLo = lowByte(intVal);
//how to calculate the checksum? I unsuccessfully tried the following
checksum = 0;
checksum = (Len+checksum+Type+intValHi+intValLo) % 256;
//send header
Serial.write(Len);
Serial.write(checksum);
Serial.write(Type);
//send sensor data
Serial.write(intValLo);
Serial.write(intValHi)
}
Thanks!
The first thing you should understand is that mod 256 is the same thing as looking at the bottom log(256) => 8 bits.
To understand this you have to first realize what the 'mod' operation does and how digits are represented in hardware.
Mod is the remainder after an old-school division (ie only with whole numbers).
eg 5%2 = 1
Digits in hardware are stored in 'bits' which can be interpreted as base 2 mathematics.
Thus if you want to take the mod operation of a power of 2 you don't actually have to do any math.
This is just like if you want to have the remainder of the power of 10, you just take the lower digits.
ie. 157 % 100 = 57.
This can be sped up by using the fact that bytes should overflow by themselves. This means that all you have to do to take %256 of a bunch of numbers is to add them to a single byte and the arduino will take care of the rest.
For twos compliment see this question:
What is “2's Complement”?

Explain concept of size of integer,character and float pointer in GCC

In GCC(Ubuntu 12 .04) Following code is the program which i need to understand for the concept of size of integer,character and float pointer.
#include<stdio.h>
main()
{
int i=20,*p;
char ch='a',*cp;
float f=22.3,*fp;
printf("%d %d %d\n",sizeof(p),sizeof(cp),sizeof(fp));
printf("%d %d %d\n",sizeof(*p),sizeof(*cp),sizeof(*fp));
}
Here i am getting following output when i run the above code in "UBUNTU 12.04"
Output:
8 8 8
4 1 4
As per this lines,"Irrespective of data types,size of pointer for address it will allow 4 bytes BY DEFAULT"
Then what is the reason behind getting sizeof(p)=8 instead it should be sizeof(p)=4....
Please explain me.
sizeof(x) will return the size of x. A pointer is like any other variable, except that it holds an address. On your 64 bit machine, the pointer takes 64 bits or 8 bytes, and that is what sizeof will return. All pointers on your machine will be 8 bytes long, regardless of what data they point to.
The data they point to may be of a different length.
int x = 5; // x is a 32 bit int, takes up 4 bytes
int *y = &x; // y holds the address of x, & is 8 bytes
float *z; // z holds the address of a float, and an address is still 8 bytes long
You're probably getting confused because you previously have done this on a 32 bit computer. You see, the 32 / 64 bit indicates the size of a machine address. So, on a 32 bit computer, a pointer holds an address that is at most 32 bits long, or four bytes. Your current machine must be a 64 bit machine, which is why the pointer needs to be 8 bytes long.
Read more about this here.
Heck, it's not just the address length. The size of other data types is also platform AND implementation dependent. For example, an int may be 16 bits on one platform & 32 bits on another. A third implementation might go crazy and have 128 bit ints. The only guarantee in the spec is that an int will be at least 16 bits long. When in doubt, always check. The Wikipedia page on C data types would be helpful.
sizeof(p) will return an address, and you are most likely running on a 64-bit machine, so your addresses will be (8*8) or 64 bits in length.
The size of the value dereferenced by p is a 32 bit integer (4*8).
You can verify this by seeing that all:
All pointers have sizeof as 8
Your char value is size 1 (typical of many implementations of c)
Print p and *p (for all variables). You will see the actual address length this way.
I'm not sure which documentation you're using but my guess is that they're talking about pointers in 32bit.
In 64 bit the size of a pointer becomes 8 bytes

Resources