XC8: .asm to C ( i.e. Lowering One's Expectations)

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
Assuming it works (not tested yet), this is insane:

C:
    asm("BANKSEL    _ws_red");
    asm("bcf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
    asm("bsf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("rlcf       _ws_blue,1,1");
    asm("rlcf       _ws_red,1,1");
    asm("rlcf       _ws_green,1,1");
    asm("bc         $+6");
    asm("bcf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("bra        $+6");
    asm("bra        $+2");
    asm("bra        $-6");
    asm("btfss"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bcf        _ws_blue,1,1");
    asm("btfsc"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bsf        _ws_blue,1,1");
    asm("decfsz     _ws_bitcnt,1,1");
    asm("bra        $-28");
    asm("bsf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
And no, @nsaspook, there is no way to write this in C that will work.

God, the hoops I have to jump through.

Ironic: I cannot write naturally in the target MCUs natural language.
 
Last edited:

nsaspook

Joined Aug 27, 2009
16,340
Assuming it works (not tested yet), this is insane:

C:
    asm("BANKSEL    _ws_red");
    asm("bcf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
    asm("bsf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("rlcf       _ws_blue,1,1");
    asm("rlcf       _ws_red,1,1");
    asm("rlcf       _ws_green,1,1");
    asm("bc         $+6");
    asm("bcf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("bra        $+6");
    asm("bra        $+2");
    asm("bra        $-6");
    asm("btfss"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bcf        _ws_blue,1,1");
    asm("btfsc"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bsf        _ws_blue,1,1");
    asm("decfsz     _ws_bitcnt,1,1");
    asm("bra        $-28");
    asm("bsf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
And no, @nsaspook, there is no way to write this in C that will work.

God, the hoops I have to jump through.

Ironic: I cannot write naturally in the target MCUs natural language.
Nothing unusual about that, that's why most embedded C compilers have asm capabilities.
 

nsaspook

Joined Aug 27, 2009
16,340
...how stupid the code looks?

This is indecipherable gibberish -- and I wrote it.

You've been spending too much time around C.
That's the truth.

C:
    /*
        Three Phase WiFi Energy Meter (WEM3080T)
    name    Unit    Description
    wem3080t_voltage_a    V    A phase voltage
    wem3080t_current_a    A    A phase current
    wem3080t_power_a    W    A phase active power
    wem3080t_importenergy_a    kWh    A phase import energy
    wem3080t_exportgrid_a    kWh    A phase export energy
    wem3080t_frequency_a    kWh    A phase frequency
    wem3080t_pf_a    kWh    A phase power factor
    wem3080t_voltage_b    V    B phase voltage
    wem3080t_current_b    A    B phase current
    wem3080t_power_b    W    B phase active power
    wem3080t_importenergy_b    kWh    B phase import energy
    wem3080t_exportgrid_b    kWh    B phase export energy
    wem3080t_frequency_b    kWh    B phase frequency
    wem3080t_pf_b    kWh    B phase power factor
    wem3080t_voltage_c    V    C phase voltage
    wem3080t_current_c    A    C phase current
    wem3080t_power_c    W    C phase active power
    wem3080t_importenergy_c    kWh    C phase import energy
    wem3080t_exportgrid_c    kWh    C phase export energy
    wem3080t_frequency_c    kWh    C phase frequency
    wem3080t_pf_c    kWh    C phase power factor
     */

    enum iammeter_phase {
        PHASE_A,
        PHASE_B,
        PHASE_C,
        PHASE_LAST,
    };

    enum iammeter_id {
        IA_VOLTAGE,
        IA_CURRENT,
        IA_POWER,
        IA_IMPORT,
        IA_EXPORT,
        IA_FREQ,
        IA_PF,
        IA_LAST,
    };

size_t iammeter_write_callback(char *buffer, size_t size, size_t nitems, void *stream) {
    cJSON *json = cJSON_ParseWithLength(buffer, strlen(buffer));

    if (json == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            fprintf(fout, "Error: %s\n", error_ptr);
        }
        goto iammeter_exit;
    }
#ifdef IM_DEBUG
    fprintf(fout, "\n iammeter_read_callback %s \n", buffer);
#endif

    cJSON *data_result = json;
    data_result = cJSON_GetObjectItemCaseSensitive(json, "Datas");

    if (!data_result) {
        goto iammeter_exit;
    }

    cJSON *jname;
    uint32_t phase = 0;

    cJSON_ArrayForEach(jname, data_result) {
        cJSON *ianame;
#ifdef IM_DEBUG
        fprintf(fout, "\n iammeter variables ");
#endif

        cJSON_ArrayForEach(ianame, jname) {
            uint32_t phase_var = 0;
            im_vars[phase][phase_var] = ianame->valuedouble;
#ifdef IM_DEBUG
            fprintf(fout, "%10.2f ", im_vars[phase][phase_var]);
#endif
            phase_var++;
        }
        phase++;
    }
#ifdef IM_DEBUG
    fprintf(fout, "\n");
#endif

iammeter_exit:
    cJSON_Delete(json);
    return size * nitems;
}

void iammeter_read(void) {

    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://10.1.1.101/monitorjson");
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, iammeter_write_callback);

        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
            iammeter = false;
        } else {
            iammeter = true;
        }
        curl_easy_cleanup(curl);
    }
}
Reading HTTP JSON encoded arrays into double variables for a energy control program from a WI-FI three phase energy monitor.
1708018803413.png
1708019146010.png
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
It works.

By the way, that snippet is to drive a string of WS2813s, if anyone is interested.

This is the function for 1 LED:

C:
typedef union
{
    uint_fast24_t rgb;
  
    struct
    {
        uint_fast8_t    blue;
        uint_fast8_t    green;
        uint_fast8_t    red;

    } color;
} triled_t;

void ColorLEDPut(triled_t led)
{
    uint_fast8_t ws_red;
    uint_fast8_t ws_green;
    uint_fast8_t ws_blue;
    uint_fast8_t ws_bitcnt;

    ws_red=led.color.red;
    ws_green=led.color.green;
    ws_blue=led.color.blue;
  
    ws_bitcnt=24;
  
    asm("BANKSEL    _ws_red");
    asm("bcf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
    asm("bsf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("rlcf       _ws_blue,1,1");
    asm("rlcf       _ws_red,1,1");
    asm("rlcf       _ws_green,1,1");
    asm("bc         $+6");
    asm("bcf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("bra        $+6");
    asm("bra        $+2");
    asm("bra        $-6");
    asm("btfss"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bcf        _ws_blue,1,1");
    asm("btfsc"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bsf        _ws_blue,1,1");
    asm("decfsz     _ws_bitcnt,1,1");
    asm("bra        $-28");
    asm("bsf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
}
ColorLEDPut() is called once for each LED in the string. A >280uS delay between calls resets string back to LED 0.

This is written for PIC18F running at 64MHz. It will not work with slower clocks.
 
Last edited:

nsaspook

Joined Aug 27, 2009
16,340
It works.

By the way, that snippet is to drive a string of WS2813s, if anyone is interested.

This is the function for 1 LED:

C:
typedef union
{
    uint_fast24_t rgb;

    struct
    {
        uint_fast8_t    green;
        uint_fast8_t    red;
        uint_fast8_t    blue;
    } color;
} triled_t;

void ColorLEDPut(triled_t led)
{
    uint_fast8_t ws_red;
    uint_fast8_t ws_green;
    uint_fast8_t ws_blue;
    uint_fast8_t ws_bitcnt;

    ws_red=led.color.red;
    ws_green=led.color.green;
    ws_blue=led.color.blue;

    ws_bitcnt=24;

    asm("BANKSEL    _ws_red");
    asm("bcf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
    asm("bsf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("rlcf       _ws_blue,1,1");
    asm("rlcf       _ws_red,1,1");
    asm("rlcf       _ws_green,1,1");
    asm("bc         $+6");
    asm("bcf"       ___mkstr(BANKMASK(LATD)) ",3,0");
    asm("bra        $+6");
    asm("bra        $+2");
    asm("bra        $-6");
    asm("btfss"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bcf        _ws_blue,1,1");
    asm("btfsc"     ___mkstr(BANKMASK(STATUS)) "," ___mkstr(_STATUS_C_POSITION) ",0");
    asm("bsf        _ws_blue,1,1");
    asm("decfsz     _ws_bitcnt,1,1");
    asm("bra        $-28");
    asm("bsf"       ___mkstr(BANKMASK(INTCON0)) "," ___mkstr(_INTCON0_GIE_POSITION) ",0");
}
ColorLEDPut() is called once for each LED in the string. A >280uS delay between calls resets string back to LED 0.

This is written for PIC18F running at 64MHz. It will not work with slower clocks.
Good job but nothing really silly or complex about that. asm is the tool for that sort of job sub-section.
 
Last edited:

cmartinez

Joined Jan 17, 2007
8,783
The worst part: converting my floating point math library to C (as inline assembly) is going to be a bee with an itch.
Knowing what you know now ... is there any kind of application out there in which you would think that using C would be a better choice than assembly? ... and I mean MCU's of course, not computers or the like.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
Knowing what you know now ... is there any kind of application out there in which you would think that using C would be a better choice than assembly? ... and I mean MCU's of course, not computers or the like.
I'm sure there is. But not in my line of work.

Edit: actually, there is no such thing a "choice" anymore, at least with respect to Microchip. And not for any technical reasons.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334

nsaspook

Joined Aug 27, 2009
16,340
There is no technical reason why C cannot support arbitrarily sized floats.

I don't like my capabilities being limited by the whims of the author of the compiler.
That's why C makes it easy to have you own libs and asm within the source code with very few limits. The expert programmer knows best what's good for their project, not some computer science priest enforcing the latest theocratic rules from the latest language designed to straitjacket what you can do because they think something is 'ugly'.

1708047247172.png
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
That's why C makes it easy to have you own libs and asm within the source code with very few limits. The expert programmer knows best what's good for their project, not some computer science priest enforcing the latest theocratic rules from the latest language designed to straitjacket what you can do because they think something is 'ugly'.

View attachment 315349
In that case, then, the IDE is the straight jacket.
 

nsaspook

Joined Aug 27, 2009
16,340
In that case, then, the IDE is the straight jacket.
No, the IDE is a supporter. It helps to protect precious things in battle.The small restriction can help you make the distance during heavy lifting.

Going Commando is cool until ...
On the ship we would Go Commando when we didn't have fresh clean water to wash clothes. We would tie pants and shirts to a rope and hang them over the fantail underway. No undies reduced the fungus in the tropics.
 
Last edited:
Top