RobertK66 / obc_1769_core

Implements hardware abstractions and Layer2(3) modules for usage of the OBC hardware in cubesat projects
GNU General Public License v3.0
1 stars 1 forks source link

PSU datavector parser #55

Open kodsurf opened 2 years ago

kodsurf commented 2 years ago

I made general skeleton for PSU datavector parser https://github.com/RobertK66/obc_1769_core/commit/c4c80a34cd256a53cbaf00a9ee6121f1933c63bc

using the same method that I applied to parsing data from thruster registers.

PSU subsustem currently does not provide any real data! Only fake rubbish bytes.

PSU datavector is uint8_t array of bytes.

But values that are "encoded" by that datavector are not uint8_t !

Example from "Communication_Procedure_OBC_to_PSU_V2.doc" at https://github.com/DominicRichter/CLIMB_PSU

image

Something called "Edge temperature" is assembled out of two uint8_t bytes (low, high) into uint16_t value.

Temperature should in the end be represented as (270.5K) double unit measured in [K]

To obtain real physical value from datavector representation there should be something like CONVERSION_FACTOR

VALUE_UINT16 = (received_data[1] <<8 )| received_data[0]; double REAL_VALUE= VALUE_UINT16_t / CONVERSION_FACTOR

Example 1 :

We want to store 270.5 K as 2705

Which is hex 0x0A91

and can be represented with two bytes 0x0A and 0x91

Example 2 :

we obtain and asseble hex 0x0A91 out of received_data[0] , received_data[1] (which are two bytes in datavector)

store it as VALUE_UINT16 = 2705

now to obtain : ACTUAL_VALUE = 2705 /100 = 270.5

where CONVERSION_FACTOR = 100


Those conversion factors have to be documented by PSU designers !!!

kodsurf commented 2 years ago

Some info that I found on registers of PSU in Pegasys project.

https://github.com/RobertK66/PEGASUS-readonly/blob/develop/OBC_FP2_FreeRTOS/Source/layer2/inc/obc_eps.h

This seems to be in accordance .. image


This also looks like in correlation image

kodsurf commented 2 years ago

`RetVal eps_settings_set(uint8_t cc, uint8_t reg, uint8_t val) { / Set the specified register (reg) of the EPS to the given value (val). /

static I2C_Data job =
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
static uint8_t tx[2];
uint32_t counter;

if ((reg < 64) || (reg > 87))
{
    /* Register number out of bounds */
    return FAILED;
}

if ((reg >= 64) && (reg <= 72))
{
    val = (val << 1) | odd_parity_calc(val);
}

if (cc == CC1)
{
    job.device = LPC_I2C0;
}
else
{
    job.device = LPC_I2C2;
}

/*--- Set resolution --- */
tx[0] = reg;
tx[1] = val;

job.adress = I2C_ADR_EPS;
job.tx_data = tx;
job.tx_size = 2;
job.rx_data = NULL;
job.rx_size = 0;

if (i2c_add_job(&job))
{
    return FAILED;
}

/* Wait for job to finish */
counter = 0;
while ((job.job_done != 1) && (counter < 50))
{
    delay_ms_all(2);
    counter++;
};

if (counter >= (50 - 1))
{
    return FAILED; /* Timeout while waiting for job */
}

if (job.error != I2C_ERROR_NO_ERROR)
{
    return FAILED;
}

return DONE;

}`

It seems that internal registers of PSU can be changed by two byte TX message (register index, value)

kodsurf commented 2 years ago

`void eps_settings_read_all(uint8_t cc) { static I2C_Data job_tx = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; static I2C_Data job_rx = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; static uint8_t tx[1];

if (job_rx.job_done != 1)
{
    /* Old job not finished - prevent job data from being  - please slow down */
    if (cc == CC1)
    {
        obc_error_counters.i2c0_error_counter++;
    }
    else
    {
        obc_error_counters.i2c2_error_counter++;
    }

    eps_settings_data.data_valid = 0;
    job_rx.job_done = 1; // Set for next call
    job_rx.error = I2C_ERROR_JOB_NOT_FINISHED; // Set error to mark values old
    return;
}

if (job_rx.error != I2C_ERROR_NO_ERROR || job_tx.error != I2C_ERROR_NO_ERROR)
{
    /* Transmission error */
    eps_settings_data.data_valid = 0;
}
else
{
    eps_settings_data.data_valid = 1;
}

if (cc == CC1)
{
    job_tx.device = LPC_I2C0;
    job_rx.device = LPC_I2C0;
}
else
{
    job_tx.device = LPC_I2C2;
    job_rx.device = LPC_I2C2;
}

tx[0] = 64; /* Current Limit HV ... Nr. 64 */

job_tx.adress = I2C_ADR_EPS;
job_tx.tx_data = tx;
job_tx.tx_size = 1;
job_tx.rx_data = NULL;
job_tx.rx_size = 0;

i2c_add_job(&job_tx);

job_rx.adress = I2C_ADR_EPS;
job_rx.tx_data = NULL;
job_rx.tx_size = 0;
job_rx.rx_data = &(eps_settings_data.current_lim_hv);
job_rx.rx_size = 24;

if (i2c_add_job(&job_rx))
{
    if (cc == CC1)
    {
        obc_error_counters.i2c0_error_counter++;
    }
    else
    {
        obc_error_counters.i2c2_error_counter++;
    }
}

}`


I would try to take a closer look into PEGASUS EPS functions in order to understand how it was implemented there

image

It looks like this line 386 already works as a parser

data stored in received bytearray is recorded directly into structure that is meant to keep this data.

image

it is seen that RX size is 24

image

and number of bytes within the structure is indeed 24 + 1 (data_valid, whic seems to be not used)

RobertK66 commented 2 years ago

Some notes about the 'data_valid' variable. During design of PEGASUS there was an effort made to get a 'secure data layer' somehow. The idea was that most stuff was available in a redundant way (2x I2C buses to EPU, 2x STACIES as comm interface, ....).

You can find this everywhere in this code. E.g. when reading values (of this 'layer') there is always a related 'valid bit' somewhere. But as this design was not thought through very well (especially what a higher layer should really do with that additional information ....) and it was completely untested at the time I entered the project, we decided to abandon it at this stage!

kodsurf commented 2 years ago

Ok ....

The bytes from PSU datavector are loaded dirrectly into the structure that should keep them. This is done in layer2 of PEGASYS

But I am really struggling to figure out what happens next ....

To convert from raw bytes of uint16 to something usefull my_val is used ? image

Are we sure that we dont want to do it the same way as done in enpulsion thruster. (with conversion multiplier table) and all values are stored as global double -representing value in physical units ?

kodsurf commented 2 years ago

Ok I see that there is a library for MATH with fix16_t type.

Assuming that we store in memory fix16_t instead of double . And use conversion function image

In Application layer of SW (when we need to compute and take an action based on physical value)

looks like I understood idea behind it .

But what are those q2_13_to_fix16() ?

image

kodsurf commented 2 years ago
How_it_works

Is this how PSU data parser supposed to work ?

kodsurf commented 2 years ago

So this EPS_MVAL_HK_I_PV1_5V is stored as some strange q2_13 ? What is q2_13

image

So datavector[2] and datavector[3] is a "q2_13" representation of i_p1_5v ???? image

So there should be a table that says that

EPS_HK_I_PV1_5V is stored at register 2 as some "q2_13" representation (whatever it is) image

RobertK66 commented 2 years ago

yea, this was a 'strange' conversion to 'fixed format' to have floats in 16bit values, to compress them for beacon and so on....

I would leave this for one discussion point for tomorrow. This (datatypes valid to be used!) has to be decided on a general level. Exactly this kind of confusion was triggering the famous ARIANE crash (as far as I can remember this ) :-)

kodsurf commented 2 years ago

Ok

image

What is the correct syntaxis with pointers ?

I want to assign bytes stored at uint8_t i2c_buffer[] to the structure of eps_hk_data_t

so that i2c_buffer[0] and i2c_buffer[1] would become :

image


The pointer to HK_DATA_PSU structure should become and address of &i2c_buffer

image

But how ?

kodsurf commented 2 years ago

https://github.com/RobertK66/obc_1769_core/commit/09b12c2d93663f580ada2407cc98a7435bb93b74

Old pegasys EPS request seem to be working correctly with CLIMB OBC and "that thing" EPS that is currently connected to it.

By "Working correctly" I mean that eps_hk_data_t structure is filled with the same values as custom parser that I made before.

If basic stuff pegasus EPS stuff works - then the rest should also be ok. Just needs to be integrated back to CLIMB.

So I see options here :

1) Integrate existing Pegasys EPS - and make proper documentation along the process. ( detailed description of protocol, request, datastructure, parser ..etc ) (?if this docu does not exists already ?)

Because now what I do - is trying to recreate EPS docu based on reverse engineering old pegasys repo. Still this EPS thing remains a total black box mistery to me. And I am collecting bits of information about it based on C code ...

image Basically I am trying to GUESS what EPS is supposed to do - based on name o variables ....

2) If EPS SW was or will be redesigned -there should be separate discussion about it to clarify how to adopt OBC code for SW and HW updates of EPS

kodsurf commented 2 years ago

image

q2_13

Does it mean that : 2 bits are used to encode integer 13 bits are used to encode floating point 1 -bit are used to encode + or - sign

So it can store [4] values as integer part and [8192] values as floating part ?

uq3_13 means that :

3bits are used to encode integer 13 bits floating point

So it can store [8] values as integer part and [8192] values as floating part, only positive numbers


image

to store current int16 ---> +/-[0,1,2,3].999 A

to store voltage uint16_t [0,1,2,3,4,5,6,7].999 V

image

Temperature : q7_8 :

[0-127].[0-99] C so maximum temperature that we are able to store is 127.99C

Is that how it is supposed to work !?!?!?!??!?!??!???!?!?!?

kodsurf commented 2 years ago

image

Multiplication of value by 2 means shifting binary bit to the left by 1 position.

Mupliply by 8 means shift by 222 = 3 positions to the left

..etc

kodsurf commented 2 years ago

image

for fix16_t datatype fractional part is represented by 8 bits image

Meaning that Radix point is at 8th bit.

so if we have uq3_13 meaning that fractional part is represented with 13bits

To convert to fix16 we must shift left by remaining 3 bits which represented an integer part (which is multiply by 8)

kodsurf commented 2 years ago

Lets take it in reverse order :

1) if we convert (double) value [real physical value] into fix16_t (using libraries fix16.h)
2) To obtain uq3_16 from fix16_t we must SHIFT LEFT by 3 bit position ? 3) Split resulting 16bit into two uint8_t

Those two MSB, LBS uint8_t would represent how the value is stored in PSU datavector[1] ,datavector[2]

2 things left to do :

  1. GET EXAMPLE OF REAL DATAVECTOR bytes !!!!!!!! and apply what is written above to convert it into real value to verify its correct and makes sense

  2. Make a table that will indicate in which binary representation (uq3_13, uq8_8 ... etc) the data from EVERY PSU REGISTER is stored

kodsurf commented 2 years ago

fix16_t is uint32_t and according to Q format it is q15_16

To convert from any other Q format into fix16_t (u15_16) do binary shift to the left so that radix point is at 17th position (from left)

image

fix16_t value of 1 = 0x10000 and binary 00000000000000010000000000000000

RobertK66 commented 2 years ago

ok, I never dived that deep into this 'fixed_xx' binary formats of EPS. I do not know what the exact intention of this format was ('Ease of use', 'compact bitwise format', 'avoid usage of float library functions', ....)

I think we should/could ask the original EPU developer about this intentions and then we can decide together with Andi (@AndiHilftnix ?) what to do with this values in the CLIMB context - and define the Climb PSU Interface definition.

kodsurf commented 2 years ago

Based on pegasys repo

<html xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">

Software reference | Register index | Description | Binary format -- | -- | -- | -- EPS_HK_I_PV2_5V | 0 | Current through FET3-2 between PV2-bus and 5V converter,low byte | q2_13 EPS_HK_I_PV1_5V | 2 | Current through FET3-1 between PV1-bus and 5V converter, low byte | q2_13 EPS_HK_V_PV2 | 4 | Voltage at PV2-bus,low byte | uq3_13 EPS_HK_V_5V_IN | 6 | Voltage at the input of the 5V converter measured at FET3-1,low byte | uq3_13 EPS_HK_I_PV1_3V3 | 8 | Current through FET5-1 between PV1-bus and 3V3 converter,low byte | q2_13 EPS_HK_I_PV2_3V3 | 10 | Current through FET5-2 between PV2-bus and 3V3 converter,low byte | q2_13 EPS_HK_V_PV1 | 12 | Voltage at PV1-bus,low byte | uq3_13 EPS_HK_V_3V3_IN | 14 | Voltage at the input of the 3V3 converter measured at FET5-2,low byte | uq3_13 EPS_HK_TEMP_BAT1SW | 16 | Temp near BAT1 switches low byte | q7_8 EPS_HK_TEMP_5V | 18 | Temp near 5V converter low byte | q7_8 EPS_HK_I_PV1_HV | 20 | Current through FET4-1 between PV1-bus and HV supply,low byte | q2_13 EPS_HK_I_PV2_HV | 22 | Current through FET4-2 between PV2-bus and HV supply,low byte | q2_13 EPS_HK_V_3V3_OUT | 24 | Voltage at the output of the 3V3 converter,low byte | uq3_13 EPS_HK_V_HV | 26 | Voltage at the output of the HV supply to the PPTs measured at FET4-2,low byte | uq3_13 EPS_HK_I_PV2_BAT1 | 28 | Current through FET1-2 between PV2-bus and battery 1,low byte | q2_13 EPS_HK_I_PV1_BAT1 | 30 | Current through FET1-1 between PV1-bus and  battery 1,low byte | q2_13 EPS_HK_V_5V_OUT | 32 | Voltage at the output of the 5V converter,low byte | uq3_13 EPS_HK_V_BAT1 | 34 | Voltage of the battery 1,low byte | uq3_13 EPS_HK_I_PV2_BAT2 | 36 | Current through FET2-2 between PV2-bus and battery 2,low byte | q2_13

<html xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">

<html xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">

EPS_HK_I_PV1_BAT2 | 38 | Current through FET2-1 between PV1-bus and  battery 2,low byte | q2_13 -- | -- | -- | -- EPS_HK_VCC_MC | 40 | Supply voltage of the MC | uq3_5 EPS_HK_TEMP_MC | 41 | Temperature of the internal sensor of the MC | int EPS_HK_V_BAT2 | 42 | Voltage of the battery 2,low byte | uq3_13 EPS_HK_TEMP_BAT1 | 44 | Temp of BAT1 on the battery holder,low byte | q7_8 EPS_HK_TEMP_BAT2 | 46 | Temp of BAT2 on the battery holder,low byte | q7_8 EPS_HK_STATUS_1 | 48 | B7 (MSB): 3V3-1 on  B6: 3V3-2 on | uint8_t EPS_HK_STATUS_2 | 49 | /* B7 (MSB): Power Low Warning (EPS will enter in Power Down Mode soon after this warning), B6: Bat1 connected to PV1 | uint8_t EPS_HK_STATUS_3 | 50 | /* B7 (MSB): 3V3 Burst Mode on, B6: 5V Burst Mode on | uint8_t EPS_HK_STATUS_BAT1 | 51 | Estimation of the remaining capacity of the Battery 1 | int EPS_HK_STATUS_BAT2 | 52 | Estimation of the remaining capacity of the Battery 2 | int EPS_HK_REBOOT_MC | 53 | Number of reboots since RBF of the main controller | int EPS_HK_REBOOT_CC1 | 54 | Number of reboots since RBF of the first communication controller | int EPS_HK_REBOOT_CC2 | 55 | Number of reboots since RBF of the second communication controller | int EPS_HK_VCC_CC1 | 56 | Supply voltage of CC1 | uq3_5 EPS_HK_TEMP_CC1 | 57 | Temperature of the internal sensor of CC1 | int EPS_HK_VCC_CC2 | 58 | Supply voltage of CC2 | uq3_5 EPS_HK_TEMP_CC2 | 59 | Temperature of the internal sensor of CC2 | int EPS_HK_STATUS_CC1 | 60 | B7 (MSB)-B6: CC Mode: 00 Boot Mode, 01 Flight Mode | uint8_t EPS_HK_STATUS_CC2 | 61 | B7 (MSB)-B6: CC Mode: 00 Boot Mode, 01 Flight Mode | uint8_t EPS_HK_CC_ID | 62 | 0xAB | uint8_t EPS_HK_TBD | 63 | Not Used |  

kodsurf commented 2 years ago

image

image

image