Mbed - struggling with exercise

Thread Starter

XDossier

Joined Jun 22, 2022
4
Hello, world, I'm a student and I have some exercise to do which is very hard (to me) and I'm struggling with finding a solution. Is there anyone here who can help me solve this 3 exercises?

Ispit_zadatak1.PNGIspit_zadatak2.PNGIspit_zadatak3.PNG
 

Irving

Joined Jan 30, 2016
3,843
Why are they hard for you? These look like fairly straightforward questions for a basic embedded programming course. Assuming you've covered these or similar aspects in the course and you have a reasonable knowledge of C++ or similar you should be able to do them.

The rule here is that its Homework Help not Homework "done for you", so you need to show your attempt at answering the questions and we'll be happy to assist further.

Anyway, I'm feeling generous, so as a starter here's some guidance on answering the questions:

Question 1 is an exercise in packing data from several variables into a data packet. Even if you know nothing about CANBus protocol it shouldn't be hard to make a stab at it assuming you have some notion of arrays and pointers. However to complete it you will need to have some knowledge of the CANBus library of your embedded platform (since its assumed in the question) or make up something reasonable that demonstrates sending a packet of data with an ID field.

Question 2 looks at how a byte of data sent and received on a serial link appears on the data lines as a sequence of 1s and 0s. Knowledge of how a UART works and typical start/stop sequences is needed.

Question 3 assumes some knowledge of I2C protocol but again even without knowledge of I2C you can figure out that you send an address then read some data a byte at a time where the 1st byte received is the length of the data stream. Use the CRC routine given to validate the byte array and return 1 or 0 depending on whether the CRC byte matches or not.
 
Last edited:

Thread Starter

XDossier

Joined Jun 22, 2022
4
Thank you Irving for advice! This is my last faculty course and when I pass this, I have degree. But, I'm not into programming so I find this hard to solve because I'm not so interested in embedded programming to be honest.
I'm completely bad in embedded programming and I was lazy to study when we had this type of programming on college. I tried something with the help of internet, but I'm not really sure if this is the right solution for this exercises. Here is 1st exercise:
View attachment 270166

Don't know how to write errors and how to write "The function must return 0 if not sent, otherwise 1".

I will try to at least solve the last 2 exercises and maybe get the right solution. Thanks in advance. Cheers, Luka
 

Attachments

ApacheKid

Joined Jan 12, 2015
1,533
Thank you Irving for advice! This is my last faculty course and when I pass this, I have degree. But, I'm not into programming so I find this hard to solve because I'm not so interested in embedded programming to be honest.
I'm completely bad in embedded programming and I was lazy to study when we had this type of programming on college. I tried something with the help of internet, but I'm not really sure if this is the right solution for this exercises. Here is 1st exercise:
View attachment 270166

Don't know how to write errors and how to write "The function must return 0 if not sent, otherwise 1".

I will try to at least solve the last 2 exercises and maybe get the right solution. Thanks in advance. Cheers, Luka
I personally think you need to step out of your comfort zone here, what degree are you studying for anyway?
 

Irving

Joined Jan 30, 2016
3,843
Thank you Irving for advice! This is my last faculty course and when I pass this, I have degree. But, I'm not into programming so I find this hard to solve because I'm not so interested in embedded programming to be honest.
I'm completely bad in embedded programming and I was lazy to study when we had this type of programming on college. I tried something with the help of internet, but I'm not really sure if this is the right solution for this exercises. Here is 1st exercise:
View attachment 270166

Don't know how to write errors and how to write "The function must return 0 if not sent, otherwise 1".

I will try to at least solve the last 2 exercises and maybe get the right solution. Thanks in advance. Cheers, Luka
Hi Luka

It's an interesting response but, ummm, how can I put this, somewhat wide of the mark. It's clear there are some fundamental concepts you need to grasp, both in terms of the way data is transmitted and also how to program for this. I've put together a short tutorial which may help and I'll send it over later today when I'm out of this meeting.

In the meantime, put up your stab at #2...
 

Irving

Joined Jan 30, 2016
3,843
BTW, I teach Mech-eng, electronics and software development, aka Mechatronics at MSc level and I'd argue it's a more valuable discipline than web and "IT" going forward - I've being doing both for over 30y...
 
Last edited:

Thread Starter

XDossier

Joined Jun 22, 2022
4
Thanks for your time. I agree I can have better future with mechatronics degree than IT degree. I'm still young (22) and I personally think I have at least 1 or 2 more years to put my ideas together and choose in which way should I go. Thanks.
 

Irving

Joined Jan 30, 2016
3,843
Thank you Irving for advice! This is my last faculty course and when I pass this, I have degree. But, I'm not into programming so I find this hard to solve because I'm not so interested in embedded programming to be honest.

I'm completely bad in embedded programming and I was lazy to study when we had this type of programming on college. I tried something with the help of internet, but I'm not really sure if this is the right solution for this exercises. Here is 1st exercise:

View attachment 270166

Don't know how to write errors and how to write "The function must return 0 if not sent, otherwise 1".

I will try to at least solve the last 2 exercises and maybe get the right solution. Thanks in advance. Cheers, Luka
Hi Luka, Since your attempt was a little off the mark, there's clearly a lot of background you need to catch up on. So in this tutorial I've probably given more direction and left less to the reader than normal or that some on AAC would accept. But there's still work for you to do to make it a complete answer.

A CANBus data frame message comprises an ID (11 or 29 bits) and a data packet of up to 64 bits (always a multiple of 8bits, so 0 to 8 bytes). I think there is an error in the problem statement when it says 'bytes', I'm sure it means 'bits' else it makes no sense. Though there are many other bits of information, most CAN libraries provide a routine that accepts an ID and a data field and will fill in the rest as needed. Note that the ID is not an address to send to, its an identifier of the message type. The message is deemed to have been sent as long as as the ACK bit is pulled low by some bus node, the sender leaves it high (passive) and watches for it to be pulled low (the dominant state) by someone. The fact its been acknowledged does not mean its being, or going to be, acted upon. Often an acknowledging response frame has the same or a very similar ID.

1656421280387.png(source)

But we will use a 48 bit data field and a 29bit ID field.

My take on this is that, as per the info given, there are a bunch of globals:, defined elsewhere:


Code:
unsigned char enable;
unsigned char error;
.
.
short inCur;
short inPwr;
and we need to access these in a routine with the prototype:

int send_to_can(void);

and package them in a 6-byte long array of bytes because 6 bytes = 48 bits:

byte data_to_send[6]; looking like:

1656421590788.png
Note that as drawn the Most Significant Byte (MSB) and MS bit (MSb) are to the right, but when printed the MSB/MSb are often on the left.

One way, most conventionally, as it works in most languages and on most platforms, to do this is bit-wise manipulation, and shifting. We'll do this with a 64bit data type "long long" (8 bytes) as there isn't a 48 bit one, and we'll map it to 6 bytes later.
Code:
// initialise some global values
inPwr = 0x1234;
inCur = 0xF99;
error = 0x1;
enable = 0x1;

long long result; // the 64bit variable to build the data packet in...

result = inPwr;
//After result = inPwr:   00000000 00000000 00000000 00000000 00010010 00110100

result <<= 12; //shift up 12 to make room for next field (inCur)
//After result <<= 12:   00000000 00000000 00000001 00100011 01000000 00000000

result |= (inCur & 0FFF); //mask off lower 12 bit and bit-wise OR into result
//After result |= inCur:   00000000 00000000 00000001 00100011 01001111 10011001

result <<= 12; //shift up 12 to make room for next field (inVolt)
//After result <<= 12:   00000000 00010010 00110100 11111001 10010000 00000000
.
.
//After setting inVolt, status, inOC, inOV, inUV (all to 0 and shifting appropriately, exercise for reader to complete):
//After further shifts:   00001001 00011010 01111100 11001000 00000000 00000000

result |= (error & 0x01); //mask off lsb and bit-wise OR into result
//After result |= error: 00001001 00011010 01111100 11001000 00000000 00000001

result <<= 1;
//After result <<= 1:    00010010 00110100 11111001 10010000 00000000 00000010

result |= (enable & 0x01);  //mask off lsb and bit-wise OR into result
//After result |= enable: 00010010 00110100 11111001 10010000 00000000 00000011

//Done, phew!

Another way is to use a bit-field structure (not fully declared here, exercise for reader to complete)

Code:
struct data_to_send {
  long long _enable :1; //1 bit, bit 0
  long long _error:1; // 1 bit, bit 1
.
.
  long long_inCur:12; // bits 20 - 31 - assuming previous bits properly declared = 2^12 = 0 - 4095
  long long_inPwr:16; // bits 32 - 47 -> 2^16 = 0 - 65535
};
so now we can write:
Code:
data_to_send._enable = enable; // simple copy LSb of global to data packet bit 0
//After data_to_send._enable = enable: 00000000 00000000 00000000 00000000 00000000 00000001 
.
data_to_send._inPwr = inPwr; // maps global short bits 0-15 to 16 bit element
//After data_to_send._inPwr = inPwr:   00010010 00110100 00000000 00000000 00000000 00000001

data_to_send._error = error;
//After data_to_send._error = error:   00010010 00110100 00000000 00000000 00000000 00000011
The big advantage of the structure over the bit-wise shifting approach is we can access the fields in any order and change them without rebuilding the whole result, which makes it much more useful for repeat messages to the same ID and of course its far more readable and easy to understand and debug.

We have to use a 'long long' to declare the individual items, even 1 bit items, to ensure there are no difficulties with bit/byte boundaries as some items span bytes. This only works if the data is always justified to the least significant bit i.e. true = 0x01 or 0xFF not 0x80. Also the values for inVolt, InCur and inPwr are considered +ve integers so no attempt has been made to reinstate the sign bit after truncating the short from 16 to 12 bits. Technically, these should have been declared as unsigned short.

Now we need to map our variable, whether a simple variable or a structure to a byte array for transmission. There are various constructs that can be used to map a variable of one type onto another in C++. One approach is to declare a UNION of two variables that share the same locations in memory. For example a 'short' is two bytes (normally) so we can write:


union map_it{
short val;
byte data[4];
};

which maps a 2 byte short onto a 4 byte array, so the lower byte of the short can be accessed as data[0], and the upper byte as data[1]. Bytes data[2] and data[3] are not used but exist as placeholders. Data can be put there but will not be seen by the 'short' variable.

So we can declare our bit structure as a union of a byte array, a simple variable and/or a structure of bit fields:
Code:
union data_to_send{
   byte data[6];
   long long result;
   struct {  //anonymous structure
     long long _enable :1; //1 bit, bit 0
     long long _error:1; // 1 bit, bit 1
.
.
     long long _inCur:12; // bits 20 - 31 - assuming previous bits properly declared
     long long _inPwr:16; // bits 32 - 47
   };//end structure
};//end union
Whether we use the structure or the simple variable, we can access the data as a byte array if need be:
Code:
for(int i=5; i>=0; i--){
  //do something with ...
  data_to_send.data[i];
}

So now we can put this altogether - I'm going to use the data structure version but the reader should try and complete the bit-wise version too.
Code:
int send_to_can(void){

//declare structure - partially. To do - complete declaration
  union data_to_send{
     byte data[6];
     //long long result; //not needed for structure version.
     struct {  //anonymous structure
       long long _enable:1;  //1 bit, bit 0
       long long _error:1;  // 1 bit, bit 1
.
.
       long long _inCur:12; // bits 20 - 31 - assuming previous bits properly declared
       long long _inPwr:16; // bits 32 - 47
     };//end structure
  };//end union

//copy values from globals - partially. To do, complete copy
  data_to_send._enable = enable; // simple copy LSB of global to data packet bit 0
  data_to_send._inPwr = inPwr; // maps global short bits 0-15 to 16 bit element
  data_to_send._error = error;

//send to CANBus - this is my platform's send routine which takes an ID, a byte array, and a length
// and returns 0 if the send was acknowledged, ie someone accepted it and -1 if it timed out.
  int res = sendCANMessage(ID, data_to_send.data, 6);

// return result to caller
  if (res == -1)  //failed? return 0
    return 0;

  return 1;  //if res was 0, will end up here...
};// end send_to_can
 
Top