Reading CAN message (PCAN-Router Pro FD) - c

please I have a problem with writing a code which will read a CAN message, edit it (limit to some maximum value) and then send back with same ID.
I´m using PCAN-Router Pro FD and will show you their example of such thing - basically same as mine but I have no idea what some of the numbers or operations are. [1]: https://i.stack.imgur.com/6ZDHn.jpg
My task is to: 1) Read CAN message with these parameters (ID = 0x120h, startbit 8, length 8 bit and factor 0,75)
2) Limit this value to 100 (because the message should have info about coolant temperature.)
3) If the value was below 100, dont change anything. If it was higher, change it to 100.
Thanks for any help !
Original code:
// catch ID 180h and limit a signal to a maximum
else if ( RxMsg.id == 0x180 && RxMsg.msgtype == CAN_MSGTYPE_STANDARD)
{
uint32_t speed;
// get the signal (intel format)
speed = ( RxMsg.data32[0] >> 12) & 0x1FFF;
// limit value
if ( speed > 6200)
{ speed = 6200;}
// replace the original value
RxMsg.data32[0] &= ~( 0x1FFF << 12);
RxMsg.data32[0] |= speed << 12;
}

After consulting the matter in person, we have found the answer.
The structure type of the RxMsg contains a union allowing the data to be accessed in 4-Byte chunks RxMsg.data32, 2-Byte chunks RxMsg.data16, or 1-Byte chunks RxMsg.data8. Since the temperature is located at the 8th bit and it is 1 Byte long, it can be accessed without using the binary masks, bit shifts and bitwise-logical-assignment operators at all.
// more if-else statements...
else if (RxMsg.id == 0x120 && RxMsg.msgtype == CAN_MSGTYPE_STANDARD)
{
uint8_t temperature = RxMsg.data8[1];
float factor = 0.75;
if (temperature * factor > 100.0)
{
temperature = (int)(100 / factor);
}
RxMsg.data8[1] = temperature;
}
The answer assumes that the startbit is the most significant bit in the message buffer and that the temperature value must be scaled down by the mentioned factor. Should the startbit mean the least significant bit, the [1] index could just be swapped out for [62], as the message buffer contains 64 Bytes in total.
The question author was not provided with a reference sheet for data format, so the answer is based purely on the information mentioned in the question. The temperature scaling factor is yet to be tested (will edit this after confirming it works).

Related

size of cache and calculating cache set

I'm trying to understand cache basics.
If I have
#define OFFSET_BITS (6) // 64 bytes cache line
#define SET_INDEX_BITS (5) // 32 sets
#define TAG_BITS (64 - OFFSET_BITS - SET_INDEX_BITS) //
#define NWAYS (8) // 8 ways cache.
What is the size of cache in this machine?
Is it just adding the offset, set and tag bits?
Also, lets say I have an address 0x40000100, what is the cache set for the address? How do I calculate that?
Assume you have an array, like this:
uint8_t myCache[1 << SET_INDEX_BITS][NWAYS][1 << OFFSET_BITS];
For NWAYS = 8, SET_INDEX_BITS = 5 and OFFSET_BITS = 6; the size of the array (the size of the cache) would be 16384 bytes (16 KiB).
Note that "cache size" only refers to how much data the cache can store, and excludes the cost of storing the tags needed to find the data.
The tags could be representing by a second array, like this:
myCacheTags[1 << SET_INDEX_BITS][NWAYS];
If one tag costs 53 bits, then 256 tags will cost 13568 bits; so to actually implement the cache you'd need a minimum of 18080 bytes. Of course in C (where you can't have an array of 53-bit integers) it'd cost a little more for padding/alignment (the array of tags would end up costing 64 bits per tag instead).
To find a cache line in the cache you'd do something like:
uint8_t *getCacheLine(uint32_t address) {
int setIndex = (address >> OFFSET_BITS) & (( 1 << SET_INDEX_BITS) - 1);
int myTag = address >> (OFFSET_BITS + SET_INDEX_BITS);
for(int way = 0; way < NWAYS; way++) {
if(myTag == myCacheTags[setIndex][way]) {
return myCache[setIndex][way];
}
}
return NULL; // Cache miss
}
Note: Typically the tag contains some kind of "valid or invalid" flag (in case an entry in the cache contains nothing at all), and typically the tag also contains something to represent the how recently used the cache line is (for some kind of "least recently used" eviction algorithm). The example code I've provided is incomplete - it doesn't mask off these extra bits when doing if(myTag == myCacheTags[setIndex][way]), it doesn't check any valid/invalid flag, and it doesn't update the tag to indicate that the cache line was recently used.

calculation in C for C2000 device

I'm having some trouble with my C code. I have an ADC which will be used to determine whether to shut down (trip zone) the PWM which I'm using. But my calculation seem to not work as intended, because the ADC shuts down the PWM at the wrong voltage levels. I initiate my variables as:
float32 current = 5;
Uint16 shutdown = 0;
and then I calculate as:
// Save the ADC input to variable
adc_info->adc_result0 = AdcRegs.ADCRESULT0>>4; //bit shift 4 steps because adcresult0 is effectively a 12-bit register not 16-bit, ADCRESULT0 defined as Uint16
current = -3.462*((adc_info->adc_result0/1365) - 2.8);
// Evaluate if too high or too low
if(current > 9 || current < 1)
{
shutdown = 1;
}
else
{
shutdown = 0;
}
after which I use this if statement:
if(shutdown == 1)
{
EALLOW; // EALLOW protected register
EPwm1Regs.TZFRC.bit.OST = 1; // Force a one-shot trip-zone interrupt
EDIS; // end write to EALLOW protected register
}
So I want to trip the PWM if current is above 9 or below 1 which should coincide with an adc result of <273 (0x111) and >3428 (0xD64) respectively. The ADC values correspond to the voltages 0.2V and 2.51V respectively. The ADC measure with a 12-bit accuracy between the voltages 0 and 3V.
However, this is not the case. Instead, the trip zone goes off at approximately 1V and 2.97V. So what am I doing wrong?
adc_info->adc_result0/1365
Did you do integer division here while assuming float?
Try this fix:
adc_info->adc_result0/1365.0
Also, the #pmg's suggestion is good. Why spending cycles on calculating the voltage, when you can compare the ADC value immediately against the known bounds?
if (adc_info->adc_result0 < 273 || adc_info->adc_result0 > 3428)
{
shutdown = 1;
}
else
{
shutdown = 0;
}
If you don't want to hardcode the calculated bounds (which is totally understandable), then define them as calculated from values which you'd want to hardcode literally:
#define VOLTAGE_MIN 0.2
#define VOLTAGE_MAX 2.51
#define AREF 3.0
#define ADC_PER_VOLT (4096 / AREF)
#define ADC_MIN (VOLTAGE_MIN * ADC_PER_VOLT) /* 273 */
#define ADC_MAX (VOLTAGE_MAX * ADC_PER_VOLT) /* 3427 */
/* ... */
shutdown = (adcresult < ADC_MIN || adcresult > ADC_MAX) ? 1 : 0;
/* ... */
When you've made sure to grasp the integer division rules in C, consider a little addition to your code style: to always write constant coefficients and divisors with a decimal (to make sure they get a floating point type), e.g. 10.0 instead of 10 — unless you specifically mean integer division with truncation. Sometimes it may also be a good idea to specify float literal precision with appropriate suffix.

Understanding Logic Using Iteration for Master/Slave

I took over a project from unknown predecessor who had gone without proper documents and comments.
Now I am trying to analyze his codes, but it is hard to follow up.
Basically, there are 32 channels hook up with a micro controller. What he seems like trying to do is find slave channels between 32 channels once those information is sent from a server.
call nextslave()
for (scan=0 ; (scan = nextslave(chan, scan)) != -1 ; scan++)
nextslave() looks like below
/**
* nextslave - gets the channel number of the next slave channel
* associated with the master. returns -1 if no more slaves.
* channel and start are zero-based.
*/
short nextslave(short channel, short start)
{
short mask, major, minor;
unsigned char *p;
/* fix-up the slaveflag[] index values */
major = start / 8;
minor = start % 8;
/* init a pointer into the slaveflag[] array */
p = &(chparam[channel].slaveflag[major]);
/* now let us find the next slave channel (if any) */
for (; major < (NUMCHANS / 8) ; major++, p++)
{
minor &= 0x07;
for (mask = (0x01 << minor) ; minor < 8 ; mask <<= 1, minor++)
{
if (*p & mask)
{
/* found one so calculate channel# and return */
return ((major * 8) + minor);
}
}
}
/* if we reach here then there are no (more) slaves */
return (-1);
}
What I have analyzed so far is:
start variable keeps iterating until 32 in nextslave().
when the start var is 0~7, major var is 0 and minor var changes from 0 to 7,also mask var changes 1,2,4,8,16...
When the start var is 8 ~15, major var is 1, and minor var still keep changing from 0 to 7
Keep iterating until major var becomes 4.(I don't know the meaning of major var in his codes)
In second for loop, return something if *p(pointer to values from server) & mask is true
I am not clear about general idea about what he intended to for this process. Especially, in the second for loop, if there is no match up in if(*p&mask), then go back to the first for loop. However, minor variable was being increased without clearing out like 0. So once the code hits minor &= 0x07, the processor will do bitwise with the last value of minor although major var keeps increasing.
For instance, the range of minor var is 0 to 7 and there is no match up value, so ends up becoming 7 in the second for loop. Get out of the loop and go back to the first loop and increases major var by 1. But minor var is still 7, so the second loop will start like mask =(0x01<<minor) with minor =7.
I feel like need to reset minor =0 whenever getting out the second for loop, but I don't know what he was aiming for. He just wrote down "master/slave technique".
My Questions are:
Is it correct with my analysis?
How the master/slave technique is used for 32 channels getting ADC?
Is the reset code for minor var required? whenever getting out the second for loop.
If you have any idea, please answer anything that helps me out to understand his codes.
Thanks,
Jin

Noise-cancellation with undirected microphones and different amplifiers

I have the following setup https://sketchfab.com/show/7e2912f5f8794a7b96ef3ac5930e090a (It's a 3d viewer, use your mouse to view all angles)
The box has two nondirectional electret microphones(black dots). On the ground there are some elements falling down like water or similar(symbolized by the sphere) and creating noises. On top, someone is speaking in the box. Distances are roughly accurate, so the mouth is pretty close.
Inside the box there are two different amplifiers(but the same electret microphones) with two different amplification circuits(the mouth-one is louder in general and has some normalization circuitry integrated. Long story short, I can record this into a raw audio file with 44100 Hz, 16Bit and Stereo, while the left channel is the upper, the right channel is the lower microphone amplifier output.
Goal is to - even though the electret microphones are not directed and even though there are different amplifiers - subtract the lower microphone(facing the ground) from the upper microphone(facing the speaker) to have noise cancellation.
I tried(With Datei being the raw-filename). This includes a high or low pass filter and a routine to put the final result back into a raw mono file (%s.neu.raw)
The problem is - well - undefinable distortion. I can hear my voice but it's not bearable at all. If you need a sample I can upload one.
EDIT: New code.
static void *substractf( char *Datei)
{
char ergebnis[80];
sprintf(ergebnis,"%s.neu.raw",Datei);
FILE* ausgabe = fopen(ergebnis, "wb");
FILE* f = fopen(Datei, "rb");
if (f == NULL)
return;
double g = 0.1;
double RC = 1.0/(1215*2*3.14);
double dt = 1.0/44100;
double alpha = dt/(RC+dt);
double noise_gain = 18.0;
double voice_gain = 1.0;
struct {
uint8_t noise_lsb;
int8_t noise_msb;
uint8_t voice_lsb;
int8_t voice_msb;
} sample;
while (fread(&sample, sizeof sample, 1, f) == 1)
{
int16_t noise_source = sample.noise_msb * 256 + sample.noise_lsb;
int16_t voice_source = sample.voice_msb * 256 + sample.voice_lsb;
double signal, difference_voice_noise;
difference_voice_noise = voice_gain*voice_source - noise_gain*noise_source;
signal = (1.0 - alpha)*signal + alpha*difference_voice_noise;
putc((char) ( (signed)signal & 0xff),ausgabe);
putc((char) (((signed)signal >> 8) & 0xff),ausgabe);
}
fclose(f);
fclose(ausgabe);
char output[300];
sprintf(output,"rm -frv \"%s\"",Datei);
system(output);
}
Your code doesn't take differences of path length into consideration.
The path difference d2 – d1 between the sound source and the two mics corresponds to a time delay of (d2 – d1) / v, where v is the speed of sound (330 m/s).
Suppose d2 – d1 is equal to 10 cm. In this case, any sound wave whose frequency is a multiple of 3300 Hz (i.e., whose period is a multiple of (0.10/330) seconds) will be at exactly the same phase at both microphones. This is how you want things to be at all frequencies.
However, a sound wave at an odd multiple of half that frequency (1650 Hz, 4950 Hz, 8250 Hz, etc.) will have changed in phase by 180° by the time it reaches the second mic. As a result, your subtraction operation will actually have the opposite effect — you'll be boosting these frequencies instead of making them quieter.
The end result will be similar to what you get if you push all the alternate sliders on a graphic equaliser in opposite directions. This is probably what you're experiencing now.
Try estimating the length of this path difference and delaying the samples in one channel by a corresponding amount. At a sampling rate of 44100 Hz, one centimetre corresponds to about 0.75 samples. If the sound source is moving around, then things get a bit complicated. You'll have to find a way of estimating the path difference dynamically from the audio signals themselves.
Ideas too big for a comment.
1) Looks like OP is filtering the l signal jetzt = vorher + (alpha*(l - vorher)) and then subtracting the r with dif = r - g*jetzt. It seems to make more sense to subtract l and r first and apply that difference to the filter.
float signal = 0.0; (outside loop)
...
float dif;
// Differential (with gain adjustments)
dif = gain_l*l - gain_r*r;
// Low pass filter (I may have this backwards)
signal = (1.0 - alpha)*signal + alpha*dif;
// I am not certain if diff or signal should be written
// but testing limit would be useful.
if ((dif > 32767) || (dif < -32767)) report();
int16_t sig = dif;
// I see no reason for the following test
// if (dif != 0)
putc((char) ( (unsigned)dif & 0xff),ausgabe);
putc((char) (((unsigned)dif >> 8) & 0xff),ausgabe);
2) The byte splicing may be off. Suggested simplification
// This assumes incoming data is little endian,
// Maybe data is in big endian and _that_ is OP problem?
struct {
uint8_t l_lsb;
int8_t l_msb;
uint8_t r_lsb;
int8_t r_msb;
} sample;
...
while (fread(&sample, sizeof sample, 1, f) == 1) {
int16_t left = sample.l_msb * 256 + sample.l_lsb;
int16_t right = sample.r_msb * 256 + sample.r_lsb;
3) Use of float vs. double. Usually the more limiting float creates computational noise, but the magnitude of OP's complaint suggest that this issue is unlikely the problem. Still worth considering.
4) Endian of the 16-bit samples may be backwards. Further, depending on A/D encoding the samples may be 16-bit unsigned rather than 16-bit signed.
5) The phase of the 2 signals could be 180 out from each other due to wiring and mic pick-up. Is so try diff = gain_l*l + gain_r*r.

Identifying a trend in C - Micro controller sampling

I'm working on an MC68HC11 Microcontroller and have an analogue voltage signal going in that I have sampled. The scenario is a weighing machine, the large peaks are when the object hits the sensor and then it stabilises (which are the samples I want) and then peaks again before the object roles off.
The problem I'm having is figuring out a way for the program to detect this stable point and average it to produce an overall weight but can't figure out how :/. One way I have thought about doing is comparing previous values to see if there is not a large difference between them but I haven't had any success. Below is the C code that I am using:
#include <stdio.h>
#include <stdarg.h>
#include <iof1.h>
void main(void)
{
/* PORTA, DDRA, DDRG etc... are LEDs and switch ports */
unsigned char *paddr, *adctl, *adr1;
unsigned short i = 0;
unsigned short k = 0;
unsigned char switched = 1; /* is char the smallest data type? */
unsigned char data[2000];
DDRA = 0x00; /* All in */
DDRG = 0xff;
adctl = (unsigned char*) 0x30;
adr1 = (unsigned char*) 0x31;
*adctl = 0x20; /* single continuos scan */
while(1)
{
if(*adr1 > 40)
{
if(PORTA == 128) /* Debugging switch */
{
PORTG = 1;
}
else
{
PORTG = 0;
}
if(i < 2000)
{
while(((*adctl) & 0x80) == 0x00);
{
data[i] = *adr1;
}
/* if(i > 10 && (data[(i-10)] - data[i]) < 20) */
i++;
}
if(PORTA == switched)
{
PORTG = 31;
/* Print a delimeter so teemtalk can send to excel */
for(k=0;k<2000;k++)
{
printf("%d,",data[k]);
}
if(switched == 1) /*bitwise manipulation more efficient? */
{
switched = 0;
}
else
{
switched = 1;
}
PORTG = 0;
}
if(i >= 2000)
{
i = 0;
}
}
}
}
Look forward to hearing any suggestions :)
(The graph below shows how these values look, the red box is the area I would like to identify.
As you sample sequence has glitches (short lived transients) try to improve the hardware ie change layout, add decoupling, add filtering etc.
If that approach fails, then a median filter [1] of say five places long, which takes the last five samples, sorts them and outputs the middle one, so two samples of the transient have no effect on it's output. (seven places ...three transient)
Then a computationally efficient exponential averaging lowpass filter [2]
y(n) = y(n–1) + alpha[x(n) – y(n–1)]
choosing alpha (1/2^n, division with right shifts) to yield a time constant [3] of less than the underlying response (~50samples), but still filter out the noise. Increasing the effective fractional bits will avoid the quantizing issues.
With this improved sample sequence, thresholds and cycle count, can be applied to detect quiescent durations.
Additionally if the end of the quiescent period is always followed by a large, abrupt change then using a sample delay "array", enables the detection of the abrupt change but still have available the last of the quiescent samples for logging.
[1] http://en.wikipedia.org/wiki/Median_filter
[2] http://www.dsprelated.com/showarticle/72.php
[3] http://en.wikipedia.org/wiki/Time_constant
Note
Adding code for the above filtering operations will lower the maximum possible sample rate but printf can be substituted for something faster.
Continusously store the current value and the delta from the previous value.
Note when the delta is decreasing as the start of weight application to the scale
Note when the delta is increasing as the end of weight application to the scale
Take the X number of values with the small delta and average them
BTW, I'm sure this has been done 1M times before, I'm thinking that a search for scale PID or weight PID would find a lot of information.
Don't forget using ___delay_ms(XX) function somewhere between the reading values, if you will compare with the previous one. The difference in each step will be obviously small, if the code loop continuously.
Looking at your nice graphs, I would say you should look only for the falling edge, it is much consistent than leading edge.
In other words, let the samples accumulate, calculate the running average all the time with predefined window size, remember the deviation of the previous values just for reference, check for a large negative bump in your values (like absolute value ten times smaller then current running average), your running average is your value. You could go back a little bit (disregarding last few values in your average, and recalculate) to compensate for small positive bump visible in your picture before each negative bump...No need for heavy math here, you could not model the reality better then your picture has shown, just make sure that your code detect the end of each and every sample. You have to be fast enough with sample to make sure no negative bump was missed (or you will have big time error in your data averaging).
And you don't need that large arrays, running average is better based on smaller window size, smaller residual error in your case when you detect the negative bump.

Resources