Inserting some Assembly inside C code for PIC24FJ series. - Page 1
Forum section: electronics / general

author: BrianHG
author_rank: Super Contributor
timestamp: February 19, 2018, 10:13:37 am
content: Hi, I'm using MPLABX built in C compiler. A variation of this code worked for PIC16/PIC18 variants, but, once switching over to PIC24F, 16bit cpu, MPLABX wont compile this code. I've counted the braces, but, it doesn't like it.Code:Code:void Drive_Meter(){int temp = 0;int temp2 = meter_position * 3;int temp3 = 0;for (temp=0 ; temp<24 ; temp++) {temp3 = leds;asm {bset WriteLednopbtss temp3,7bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,6bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,5bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,4bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,3bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,2bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,1bclr WriteLednopnopbclr WriteLednopnopnopnopnopnopbset WriteLednopbtss temp3,0bclr WriteLednopnopbclr WriteLed//nop//nop//nop//nop//nop//nop} //endasmtemp2++;}}Error:Code:CLEAN SUCCESSFUL (total time: 18ms)make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-confmake: Entering directory 'C:/Users/Admin/MPLABXProjects/LED_Strip_Count_PIC24FJ.X'make -f nbproject/Makefile-default.mk dist/default/production/LED_Strip_Count_PIC24FJ.X.production.hexmake: Entering directory 'C:/Users/Admin/MPLABXProjects/LED_Strip_Count_PIC24FJ.X'"C:\Program Files (x86)\Microchip\xc16\v1.33\bin\xc16-gcc.exe" mcc_generated_files/pin_manager.c -o build/default/production/mcc_generated_files/pin_manager.o -c -mcpu=24FJ128GA606 -MMD -MF "build/default/production/mcc_generated_files/pin_manager.o.d" -mno-eds-warn -g -omf=elf -DXPRJ_default=default -legacy-libc -O0 -msmart-io=1 -Wall -msfr-warn=off"C:\Program Files (x86)\Microchip\xc16\v1.33\bin\xc16-gcc.exe" mcc_generated_files/mcc.c -o build/default/production/mcc_generated_files/mcc.o -c -mcpu=24FJ128GA606 -MMD -MF "build/default/production/mcc_generated_files/mcc.o.d" -mno-eds-warn -g -omf=elf -DXPRJ_default=default -legacy-libc -O0 -msmart-io=1 -Wall -msfr-warn=off"C:\Program Files (x86)\Microchip\xc16\v1.33\bin\xc16-gcc.exe" mcc_generated_files/interrupt_manager.c -o build/default/production/mcc_generated_files/interrupt_manager.o -c -mcpu=24FJ128GA606 -MMD -MF "build/default/production/mcc_generated_files/interrupt_manager.o.d" -mno-eds-warn -g -omf=elf -DXPRJ_default=default -legacy-libc -O0 -msmart-io=1 -Wall -msfr-warn=off"C:\Program Files (x86)\Microchip\xc16\v1.33\bin\xc16-gcc.exe" main.c -o build/default/production/main.o -c -mcpu=24FJ128GA606 -MMD -MF "build/default/production/main.o.d" -mno-eds-warn -g -omf=elf -DXPRJ_default=default -legacy-libc -O0 -msmart-io=1 -Wall -msfr-warn=offmain.c: In function 'Drive_Meter':main.c:69:5: error: expected '(' before '{' token *********************************************HERE********************main.c:70:9: error: 'bset' undeclared (first use in this function) ***************************HERE**********************main.c:70:9: note: each undeclared identifier is reported only once for each function it appears inmain.c:70:18: error: expected ';' before 'PORTF'nbproject/Makefile-default.mk:148: recipe for target 'build/default/production/main.o' failedmake: *** [build/default/production/main.o] Error 255make: *** Waiting for unfinished jobs....make: Leaving directory 'C:/Users/Admin/MPLABXProjects/LED_Strip_Count_PIC24FJ.X'nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failedmake: Leaving directory 'C:/Users/Admin/MPLABXProjects/LED_Strip_Count_PIC24FJ.X'nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failedmake: *** [.build-conf] Error 2make: *** [.build-impl] Error 2BUILD FAILED (exit value 2, total time: 9s)The syntax and handling of assembly is different when dealing with 16 bit C compiler. I cant find any good documentation on mixing both. Only with 8 bit pics. This is my first mixing of code in 16 bit pic, so please be patient.

author: andersm
author_rank: Super Contributor
timestamp: February 19, 2018, 10:22:13 am
content: GCC has itsown inline assembly syntax(see alsothis HOWTO).

author: BrianHG
author_rank: Super Contributor
timestamp: February 19, 2018, 10:41:03 am
content: Ok, the brackets of:asm (blahhhhblahhhhblahhhhblahhhh);Now recognizes the inside of the brackets as assembly. Next, the first bitset.I wish to set bit 4 of PORTF. Now, I currently have:bset PORTF,4but, the compiler says 'main.c:70:9: error: expected string literal before 'bset' 'Must I seriously place every assembly line in a set of ""Quotes""Talk about a mess.

author: BrianHG
author_rank: Super Contributor
timestamp: February 19, 2018, 10:55:46 am
content: I tried the " .... " (Quotes), now I get a bunch of errors to a file I cant even access, not even part of any of my source files.

author: Kalvin
author_rank: Super Contributor
timestamp: February 19, 2018, 11:16:40 am
content: Have you checked this document "XC16 C Compiler User’s Guide":http://ww1.microchip.com/downloads/en/DeviceDoc/50002071F.pdfSee section 16.3. USING INLINE ASSEMBLY LANGUAGE, starting on page 230. Good luck!

author: BrianHG
author_rank: Super Contributor
timestamp: February 19, 2018, 11:26:59 am
content: Quote from: Kalvin on February 19, 2018, 11:16:40 amActually, it starts on page 227 if I want to be more neat about it...

author: Kalvin
author_rank: Super Contributor
timestamp: February 19, 2018, 12:26:21 pm
content: Quote from: BrianHG on February 19, 2018, 11:26:59 amI wanted to give a direct pointer to the inline asm section. But yes, you are right that the section regarding mixing C and assembly code starts at page 227.

author: JPortici
author_rank: Super Contributor
timestamp: February 19, 2018, 01:53:15 pm
content: it was my understanding that a long time ago they removed the block assembly feature and now you can only add single-lines inline assembly.You can of course get around that with newline characters "\n"but if you tell me that hitting return works, good to know!

author: Howardlong
author_rank: Super Contributor
timestamp: February 19, 2018, 02:27:49 pm
content: Quote from: JPortici on February 19, 2018, 01:53:15 pmI'm not sure if it ever was in XC16 or C30 (ISTBC!), and these days I don't often use assembly language except at specific pinch points, but certainly looking at the last two projects I've used assembly language in I've used single liners, see an example below.Code:void IQCorr(int nSamples){/*register int i=NO_OF_BYTES_TRANSFRED_IN_A_USB_FRAME/4;signed short *ps16=_as16Buffer;while (i-->0)*/{// Preload the I/Q correction factors here to save time in the loopasm ("mov __s16PhaseCorr,W6": : : "w6");asm ("mov __u16GainCorr,W4": : : "w4");asm ("mov __s16DCICorr,W7": : : "w7");asm ("mov __s16DCQCorr,W8": : : "w8");// W1 points to the current sample starting at _asIQasm ("mov #__as16IQ,W1": : : "w1");// W5 is the loop counter, one iteration per sampleasm ("mov %0,W5": : "r"(nSamples) : "w5");asm ("loop:");// DCI correctionasm ("add W7,,W0": : : "w0"); // W0 = I + DCICorrasm ("mov W0,[W1++]": : : "w1"); // I = I + DCICorr// DCQ correctionasm ("add W8,,W9": : : "w9"); // W9 = Q + DCQCorr// Phase & gain correction Qout = (Qdccorr + (Idccorr* PhaseCorr)) * GainCorrasm ("mul.ss W6,W0,W2": : : "w2","w3"); // W3:W2 has I * PhaseCorrasm ("add W3,W9,W0": : : "w0"); // W0 has Q + (I * PhaseCorr)asm ("mul.su W0,W4,W2": : : "w2","w3"); // W3:W2 has (Q + (I * PhaseCorr)) * GainCorrasm ("sl W2,W2": : : "w2");asm ("rlc W3,W3": : : "w3"); // W3 now has corrected Qasm ("mov W3,[W1++]": : : "w1");asm ("dec W5,W5": : : "w5");asm ("bra NZ,loop");/*register signed short s16=(signed short)(__builtin_mulss(*ps16++,_s16PhaseCorr)>>16);*ps16++=(signed short)(__builtin_mulsu(*ps16+s16,_u16GainCorr)>>15);*//*signed short s16=(signed short)((((signed long)(*ps16++))*_s16PhaseCorr)>>16);*ps16++=(signed short)((((signed long)(*ps16+s16))*_u16GainCorr)>>15);*/}//Nop();}

author: JPortici
author_rank: Super Contributor
timestamp: February 19, 2018, 02:55:03 pm
content: (ISTBC? Never encountered the acronym)Quote from: Howardlong on February 19, 2018, 02:27:49 pmsame.. for example a 16/32 point Antialiasing FIR.. the microchip dsp libary require 61 cycles just for setup.. or this is what the manual says.I don't understand why,-pushing and popping all the needed WREGs is like 12 instructions total.-another dozen to set up the circular buffers-one clear with prefetch + 16/32 MACs-one to retreive the result from the accumulatorso i use my own function.Code:asm ("mov __s16DCQCorr,W8": : : "w8")could you explain how this gets translated? my knowledge of dspic assembler is just this much..

author: Howardlong
author_rank: Super Contributor
timestamp: February 20, 2018, 09:57:54 am
content: Quote from: JPortici on February 19, 2018, 02:55:03 pmISTBC = "I stand to be corrected", i.e., a caveat that my memory may be failing me!QuoteI haven't done much in recent years with dsPIC, but pretty much across the entire PIC range for exceptionally low latency interrupt handling I've found I sometimes have to hand craft ISR prolog and epilog code, even when the part has shadow registers.QuoteThis is GCC syntax and to be honest this syntax came to me relatively recently compared to my assembly language career, so I am certainly no expert in it, pretty much most of my knowledge of it comes from looking at others' examples, I should spend more time looking at the manual! The code example I gave I wrote over seven years ago!There's a 16 bit global C RAM variable called __s16DCQCorr, the contents of which are moved in the W8 register.Code:int16_t __s16DCQCorr=0;Specifying the "w8" at the end there tells the compiler that the W8 register is clobbered, i.e. overwritten, by my assembly language, so it takes that into account when compiling any C code around my ASM.In retrospect, it would probably be better (more correct) to write it like this:Code:asm ("mov %0,W8": :"U" (__s16DCQCorr) : "w8")This tells it explicitly that the variable is near.If you overwrite several registers, then you can list them, comma separated, for example:Code:asm ("mul.ss W6,W0,W2": : : "w2","w3"); // W3:W2 has I * PhaseCorrThe MUL generates a 32 bit result, so clobbers two 16 bit registers, shown in the clobber list.As stated, I am no expert in this GCC syntax, sometimes I find it easier to write the code directly into a .s.

author: JPortici
author_rank: Super Contributor
timestamp: February 20, 2018, 10:27:39 am
content: Usually when i encounter a new acronym i give it to the urbandictionary search engine, but it failed me this timeThank you for your explanation, i found it easier to understand that the relevant compiler manual chapter (16.3)which basically says the same thing in the same way but.. whatever, sometimes when somebody repeats something it stucks with you better