C: can't find words - Page 1
Forum section: electronics / general

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 06, 2020, 04:10:47 pm
content: Honestly, I've tried everything! I'm doing an exercise from my "PIC C" book to display a value with one dec pl. The book says to isolate the tenths digit, round it and display (using a PIC16F1827):#include <xc.h>#include "C:\ExPICCX8\LCD.C"#include "stdio.h"void main(void) // start of programme{float cap = 0.1;float res = 2489;float pi = 3.14159;float freq;float temp;unsigned int units;unsigned int tenths;unsigned char outstring;ANSELB = 0;TRISB = 0; // set all PORTB bits as outputsdelayinit( 4 ); // initialise delay for 4Mhz osclcdinit(); // must be after delayinit()freq = 1 / ( 15.3906 * cap / 1000000 * res );units = freq; // Converts ?float? to ?int?temp = 10 * (freq - units) + 0.5; // rounded tenthstenths = temp;lcdtop( 0 ); // cursor to top line 1st charlcdputs( "Phase shift Osc" );lcdbot( 0 );sprintf( outstring, "Freq = %d.%d Hz", units, tenths );lcdputs( outstring );while(1==1); // stop loop}This always has the compile (XC8 v2.10) error::0:: error: (1347) can't find 0x10 words (0x10 withtotal) for psect "stringtext2" in class "STRCODE" (largest unused contiguous range 0xD)Non line specific message::: advisory: (1493) updated 32-bit floating-point routines might trigger "can't find space" messages appearing after updating to this release; consider using the smaller 24-bit floating-point types:0:: error: (1347) can't find 0xD words (0xd withtotal) for psect "text16" in class "CODE" (largest unused contiguous range 0x8)However, if I change:temp = 10 * (freq - units) + 0.5; // rounded tenthsto:temp = 1; // rounded tenthseverything goes fine and it displays 261.1 as expected.I've tried everything I can think of and I just don't get it. It (the version that compiles) only uses 80% of the programme memory and 49% of data memory.Any suggestions would be most gratefully received?

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 06, 2020, 04:41:21 pm
content: Haven't used XC8 in ages, but just take a look at the error message.It suggests using 32-bit floats (the default when using the 'float' type) may trigger this kind of message. I suspect 32-bit FP routines may take too much code size in some cases.This part has a very small program memory size (7 KB!)They suggest using 24-bit floats instead. Whether they are acceptable in your application in terms of precision is yours to figure out.To enable 24-bit floats, I guess you need to enable the right compiler option. Look that up in XC8 docs.As a general rule, using floating point on very small targets that do not embed any FPU is not always a great idea. Soft-FP takes significant code size, and is slow.In your case, you can probably rewrite you calculations so they are using integers only.

author: DrG
author_rank: Super Contributor
timestamp: May 06, 2020, 05:45:25 pm
content: Give thishttps://microchipdeveloper.com/faq:45a good slow read. Then generate your map file and see where blocks (psects) are coming up short. Try breaking a function up into two smaller ones. Try using the bank qualifier on variables.Then get a larger pic

author: PlainName
author_rank: Super Contributor
timestamp: May 06, 2020, 07:56:45 pm
content: Shouldn't that 0.5 be '0.5f'? I think XC8 treats n.m as double and n.mf as float. Given all the conversions in that line it might have its knickers in a twist. I'd split the line up into separate statements for each operation and see which one is prompting the issue.

author: IDEngineer
author_rank: Super Contributor
timestamp: May 06, 2020, 10:54:10 pm
content: Quote from: SiliconWizard on May 06, 2020, 04:41:21 pmCaveat... A few years ago I tested all the various floating point widths from Microchip and the 32 bit libraries weresubstantiallyfaster than their 24 bit versions, regardless of optimization setting. I can't remember all the details now but at the time I remember being delighted that I was getting increased precision for fewer CPU cycles. I did not evaluate for code space consumption, so for the OP's situation my results may not be directly applicable. Nevertheless, the moral of the story still holds: Sometimes the results aren't as obvious as you'd think. Real life testing is well worth the one-time investment.

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 07, 2020, 05:42:43 pm
content: Thank you very much all, will try those ideas.BTW when you include a file with #include does the compiler include all the functions in that file or just the ones that are called?

author: IDEngineer
author_rank: Super Contributor
timestamp: May 07, 2020, 05:51:02 pm
content: Quote from: PerranOak on May 07, 2020, 05:42:43 pmThe linkershouldonly pull in the ones that are referenced, but oftentimes multiple functions are grouped together and when you invoke one you bring in the others even if they're not explicitly referenced. Floating point libraries are often like this. Some environments give you finer control over this behavior, you just have to do some research on the tools you're using.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: May 07, 2020, 05:59:11 pm
content: Taking out all the LCD stuff (because I don't have it) and commenting out delayinit because I don't have that either....Code:#include <xc.h>//#include "C:\ExPICCX8\LCD.C"#include "stdio.h"void main(void) // start of programme{float cap = 0.1;float res = 2489;float pi = 3.14159;float freq;float temp;unsigned int units;unsigned int tenths;unsigned char outstring;ANSELB = 0;TRISB = 0; // set all PORTB bits as outputs//delayinit( 4 ); // initialise delay for 4Mhz osc//lcdinit(); // must be after delayinit()freq = 1 / ( 15.3906 * cap / 1000000 * res );units = freq; // Converts ?float? to ?int?temp = 10 * (freq - units) + 0.5; // rounded tenthstenths = temp;//lcdtop( 0 ); // cursor to top line 1st char//lcdputs( "Phase shift Osc" );//lcdbot( 0 );sprintf( outstring, "Freq = %d.%d Hz", units, tenths );//lcdputs( outstring );while(1==1); // stop loop}Compiles to....Code:Memory Summary:Program space used EB4h ( 3764) of 1000h words ( 91.9%)Data space used C5h ( 197) of 180h bytes ( 51.3%)EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)Configuration bits used 0h ( 0) of 2h words ( 0.0%)ID Location space used 0h ( 0) of 4h bytes ( 0.0%)Not much headroom!If you also comment out the sprintf then you get down to...Memory Summary:Program space used 8DFh ( 2271) of 1000h words ( 55.4%)Data space used 80h ( 128) of 180h bytes ( 33.3%)EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)Configuration bits used 0h ( 0) of 2h words ( 0.0%)ID Location space used 0h ( 0) of 4h bytes ( 0.0%)So maybe re-write/hand-craft the conversion to the display and it will then fit?

author: DrG
author_rank: Super Contributor
timestamp: May 07, 2020, 06:46:08 pm
content: Quote from: PerranOak on May 07, 2020, 05:42:43 pmCan you attach "C:\ExPICCX8\LCD.C" to your post?

author: Howardlong
author_rank: Super Contributor
timestamp: May 07, 2020, 07:42:40 pm
content: You're out of program flash space.I don't have your LCD libraries, but even with all the LCD references commented out, 3764 of 4096 words are used without optimisations. With -Os on with the Pro XC8, it's 2698 words, but I don't recommend using -Os when you're learning, it makes debugging in particular stepping code hard.Code:Memory Summary:Program space used EB4h ( 3764) of 1000h words ( 91.9%)Data space used C5h ( 197) of 180h bytes ( 51.3%)EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)Data stack space used 0h ( 0) of B0h bytes ( 0.0%)Configuration bits used 0h ( 0) of 2h words ( 0.0%)ID Location space used 0h ( 0) of 4h bytes ( 0.0%)There are two program memory hogs here. Firstly, the use of floating point. Secondly the use of sprintf.On such a space constrained device, I'd strongly recommend against the use of both floating point and XXXprintf, and scale your data using various int types as a fixed point implementation.Or just throw a bigger processor at it (e.g., PIC16F1847 appears to be pin and peripheral compatible, but more flash and RAM), and accept about 3k+ words of overhead.(edit: sorry, I wrote this many hours ago and only just sent it).

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 08, 2020, 02:34:34 pm
content: You guys are great, thank you very much!IDEngineer, I just wondered wether the compiler included everything because it reports the functions that I didn't call in LCD.cThat memory usage, NivagSwerdna, how did you get that? Also, thank you for doing all that. I guess space is my problem.DrG, "C:\ExPICCX8\LCD.C" as requested:void delay100u( unsigned int k); // delay in units of 100 uSvoid delayinit( unsigned char freq ); // initialise delay routinevoid lcdputch( unsigned char c ); // write one character to LCDvoid lcdputs(const char *s); // write string to LCDvoid lcdwrite( unsigned char c ); // write one byte to LCDvoid lcdtop( unsigned char offset ); // set LCD to top linevoid lcdbot( unsigned char offset ); // set LCD to bottom linevoid lcdclear( void ); // clear LCD and home cursorvoid lcdinit( void ); // initialise LCD// declare global variablesstatic unsigned char cycles;// define macros#define STROBE PORTBbits.RB5=1,PORTBbits.RB5=0;#define RS PORTBbits.RB4void delay100u( unsigned int k ){while(k > 0){PR2 = cycles; // Move end count into PR2TMR2IF = 0; // Clear Timer2 interrupt flagT2CON = 0b00010100; // 1:1 clock, 1:3 postscalerwhile(TMR2IF == 0); // Wait for TMR2IF to setT2CON = 0; // Turn off Timer2k--;}}void delayinit( unsigned char freq) // initialise delay routine{cycles=30*freq/4; // 4Mhz=30, 8=60, 20=150}void lcdputch( unsigned char c ) // write one char to the LCD{RS = 1; // LCD to write charsPORTB = (PORTB & 0xF0) | (c >> 4); // send top 4 bitsSTROBEdelay100u(1);PORTB = (PORTB & 0xF0) | (c & 0x0F); // send bottom 4 bitsSTROBEdelay100u(1);}void lcdputs(const char *s) // write a string to the LCD{RS = 1;while( *s )lcdwrite( *s++ );}void lcdwrite( unsigned char c ) // write one byte to LCD{PORTB = (PORTB & 0xF0) | (c >> 4);STROBEdelay100u( 1 );PORTB = (PORTB & 0xF0) | (c & 0x0F);STROBEdelay100u( 1 );}void lcdtop( unsigned char offset ) // set LCD to top line{unsigned char data; // define local variabledata = 0x80 + offset;RS = 0; // set LCD to COM modelcdwrite( data );}void lcdbot( unsigned char offset ) // set LCD to bottom line{unsigned char data; // define local variabledata = 0xC0 + offset;RS = 0; // set LCD to COM modelcdwrite( data );}void lcdclear( void ) // clear LCD and home cursor{RS = 0; // set LCD to COM modelcdwrite( 0x01 ); // write 01 to LCDdelay100u( 160 ); // wait for LCD to clear}void lcdinit( void ) // initialise the LCD{RS = 0; // set LCD to COM modedelay100u( 150 ); // 15mS delayPORTB = 0x03;STROBEdelay100u( 50 ); // 5mS delaySTROBEdelay100u( 50 );lcdwrite( 0x32 ); // set to 4 bit modelcdwrite( 0x2C ); // set for 2 lineslcdwrite( 0x08 ); // display offlcdwrite( 0x06 ); // set increment cursorlcdwrite( 0x0C ); // display on, cur offlcdwrite( 0x01 ); // clear displaydelay100u( 16 ); // 1.6mS delaylcdwrite( 0x02 ); // home cur, clear RAMdelay100u( 16 ); // 1.6mS delay}Cheers Howardlong, willco. This is all part of a teaching project so I, sort of, have no choice about PIC or floating point, etc. However, I do want to get to the botom of this problem as a learning opportunity in itself.

author: DrG
author_rank: Super Contributor
timestamp: May 08, 2020, 03:18:47 pm
content: Quote from: PerranOak on May 08, 2020, 02:34:34 pmI stuck the included file code into the same file as main (moved the function declarations and globals up top).I changed the XC8 options to link in the C90 library (in Global and Linker options).This got rid of the psect errors and gave me a successful build. I don't have the chip and your hardware, so I can't go further. Take a look at the attached logging / mapping file. I don't see any space problems, but note this:BANK0 used 50h ( 80) of 50h bytes (100.0%)See link in my first message as you may be able to move some thinks using the bank prefix declarations, but I don't think that you have to for testing.Can you see if you can get it working with the changes to C90 from C99 (default)?I *think* but don't know and don't want to go look into it further right now, that it is linking the smaller 24 bit FP libs in contrast to the larger 32 bit FP libs - does anyone know if that is the case?You should get rid of those implicit conversion warnings. Also note a couple functions that are never called.Hope this helps more than further confuses

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 08, 2020, 04:36:51 pm
content: Brilliant, thank you DrG I'll have a go.BTW when you remark that a couple of functions are not used - does this mean that all the functions in LCD.c are compiled not just the ones that are called or is it just that you've brought LCD.c into the main file in this case?

author: NivagSwerdna
author_rank: Super Contributor
timestamp: May 08, 2020, 05:09:58 pm
content: In MPLABX the memory usage code and data appears in the project dashboard and also in the output window.These are XC8 Linker... Reporting Options... "Display overall memory usage etc"Please could you post your complete code... it doesn't seem to read from anywhere... if you are not careful everything will just get optimised out. e.g. expressions that involve constants will evaluate at compile time and if they have no references they will not be linked.PSIf you don't need floating point then don't use it... use scaled calculations in integer types... e.g long FreqTimes10 = a * b * c; and then scale on output.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 08, 2020, 08:08:12 pm
content: If you are going to do embedded microcontroller work, I recommend you learn early on how to deal with fixed point numbers, completely avoiding floating point. It's almost always nearly trivial once you get used to it; actually I "accidentally" tend to use fixed point practices even when I have the luxury of an FPU.Floating point becomes a possibility on 8-bitters with approx. 8kB (preferably at least 16kB IMHO) of flash whenever the algorithm can be accepted to be a total slug, like calculating a single number for a human being to look at in realtime (in which case it doesn't matter even if it takes milliseconds to calculate).With 4kB of flash, you are wasting most of it on the software floating point library.Also note that float is 32 bits, so quite wasteful ram-wise on small 8-bitters which often have just tens to hundreds bytes of RAM, when you can often do with a 16-bit fixed point number instead if you choose the range right.

author: IDEngineer
author_rank: Super Contributor
timestamp: May 08, 2020, 08:51:36 pm
content: Quote from: PerranOak on May 08, 2020, 02:34:34 pmThe linker will include whatever you reference, PLUS whatever was "packaged" with that thing you referenced. This is why in some environments just touching a single floating point function can link in the entire FP library. Same thing is true for printf(). In the case of FP it's a complex library, and complexity requires a lot of code. In the case of printf(), it's a veryflexiblelibrary and - you guessed it - flexibility requires a lot of code!Other environments parcel their libraries into smaller linkable modules so you end up with less bloat. If you're really into it, and the library source is available, you can craft up your own custom mixture of the precise library functions you need so you don't link in anything but exactly what you want/need. Obviously that requires extra work on your part, and the dependencies can increase the footprint pretty fast so the "savings" can end up being smaller than you'd think at first glance.Which raises another option: If you do have access to the library source, you could manually copy over the source code for the function(s) you need and just freshly compile them as part of your source code, rather than #including and then linking in the existing libraries. Again, the dependencies may make this less beneficial than you'd think, but it might be worth a look.I heartily second Siwastaja's recommendation that you try to work with fixed point numerics if possible. It's both faster and has a far smaller footprint than floating point, and in many cases it works just as well. Indeed, in certain applications fixed point can be MORE ACCURATE than floating point since fixed point does not suffer from quantization errors. On the other hand, fixed point can suffer from rounding/truncation errors due to limited resolution. Like all of Engineering, it's a tradeoff that you must consider and decide.

author: DrG
author_rank: Super Contributor
timestamp: May 10, 2020, 03:11:40 pm
content: Quote from: PerranOak on May 08, 2020, 04:36:51 pmNot sure if that change made the program run, but I wanted to respond with respect to some of the other posts...I think that you have been given some decent advice and, in general I agree with it completely.When you are learning PICs, and I am assuming that you are in such a stage because your OP talks about doing an exercise from a book, one of the most important aspects to learn is that there are MANY PIC chips and MANY have been around for a while. That situation can easily result in book examples not "working" any more and it can be very frustrating.So, for instance, the example in your book may have fit and worked just fine at one time, but not anymore without some changes. Perhaps earlier versions of XC8 used, as a default, the smaller 24-bit floating point library but newer versions, as a default, use the larger 32-bit versions (note that you can even see a message about the larger 32 bit FP libraries in the output). There is no way the book example knew that at the time and for the person who later goes through the example, it can be incredibly frustrating.There is hope... I have learned to not ignore warnings (unless I completely understand the situation) and to automatically search on errors that puzzle me.Also, sometimes it is ok to avoid one size fits all "rules". Several times you asked about unused functions and whether they are compiled (thus adding to the program size). The answer is to check yourself - somebody mentioned researching the subject - I agree completely. In this case, comment out the unused functions and compare the program sizes. You will also find out very quickly whether there are some dependencies that exist.You have probably gained some appreciation for how important understanding linker messages and mapping can be.Finally, not using floating point libraries unless you really need to use them is probably sound advice since they take up so much space. That may seem daunting at first, but it is a good point to, at least, park in your mind even if you don't stop right now and figure out how to do something without the floating point libraries.End of my two cents

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 10, 2020, 04:09:21 pm
content: Yes, you’re right. I had to upgrade my manual (i.e. buy a new one) when a new version of X8C came out! I think the PIC16F1827 was chosen because it has quite a few features but is limited enough so that everything isn’t easy ... like this problem(!) I, like you, do not let things pass, hence my delving into this problem rather than just blasting on through the manual. I will look properly at the messages in future.I guess I wasn’t sure about the unused functions and so thought that some answers were contradictory I think this was my paranoia in that I’ve never seen “stdio.h” and wondered if it behaved differently from my LCD.c. This is the sort of thing that manuals don’t mention and I can’t think how to formulate a Google question for it. Still, the solution of experimenting/researching will always work, it’s true!I hadn’t realised that the floating-point vs fixed-point was an issue ... more for me to research.Thank you again.

author: DrG
author_rank: Super Contributor
timestamp: May 10, 2020, 04:32:21 pm
content: Quote from: PerranOak on May 10, 2020, 04:09:21 pmYeah, there is a lot to it but I like your inquisitive approach.Sometimes though it just does not seem fair....once using XC32, I was trying to use a 'dead' loop as a delay..for (i = 0; i < 50000; i++){}That kind of thing. Yeah, I know how to use timers for delays but in this case I just wanted to debug using a sloppy little for-next loop. It just did not work! Didn't matter if it was 50000 or a kaziillion...just would not make any difference at all - it was driving me up a wall.The compiler had decided, and without telling me, that I was too stupid to write reasonable code and simply did not compile the for next loop. At least it could have spit out a warning that said...Code Stupidity Error, do nothing code not compiled.Adding a __NOP in the loop restored sanity.

author: chriva
author_rank: Regular Contributor
timestamp: May 10, 2020, 06:34:51 pm
content: Do you have optimizations enabled?I've noticed that several compilers removes loops if no operation is performed within them.Gcc in particular may even go next level a-hole and remove inline assembler instructions if they're not declared as volatile

author: DrG
author_rank: Super Contributor
timestamp: May 10, 2020, 08:07:53 pm
content: Quote from: chriva on May 10, 2020, 06:34:51 pmNot sure I understand. But, at the risk of thread drift....I am using XC32 2.30 free.Optimization is set to 1 (likely the default). The text for optimizations is as follows (not sure all those levels are available in the free version).- 0 - Do not optimize. The compiler’s goal is to reduce the cost of compilation and to make debugging produce the expected results.- 1 - Optimize. Optimizing compilation takes somewhat longer, and a lot more host memory for a large function. The compiler tries to reduce code size and execution time.- 2 - Optimize even more. The compiler performs nearly all supported optimizations that do not involve a space-speed trade-off.- 3 - Optimize yet more favoring speed (superset of O2).- s - Optimize yet more favoring size (superset of O2).Since I do not have it set at 0, I guess the answer is Yes, I do have optimizations set on. Can't do it right now, but it is worth checking if seting it to '0' would have made a difference.Thanks

author: MarkF
author_rank: Super Contributor
timestamp: May 10, 2020, 11:21:25 pm
content: You can also set optimization levels for the free version of XC8.Level 2 has saved enough memory space for a few of my projects.Also, use the XC8 built-in delay() functions in the LCD library.It also should be broken up into header and c files.Code:/** File: lcd.h*/#ifndef __LCD_H#define__LCD_H#ifndef _XTAL_FREQ#define _XTAL_FREQ 4000000L#endif#include <xc.h>void lcdputch( char c ); // write one character to LCDvoid lcdputs( const char *s ); // write string to LCDvoid lcdwrite( unsigned char c ); // write one byte to LCDvoid lcdtop( unsigned char offset ); // set cursor to top linevoid lcdbot( unsigned char offset ); // set cursor to bottom linevoid lcdclear( void ); // clear LCD and home cursorvoid lcdinit( void ); // initialize LCD// define macros#define STROBE PORTBbits.RB5=1,PORTBbits.RB5=0;#define RS PORTBbits.RB4#endif/* LCD_H *//** File: lcd.c*/#include "lcd.h"void lcdputch( char c ) // write one char to the LCD{RS = 1; // LCD to write charsPORTB = (PORTB & 0xF0) | (c >> 4); // send top 4 bitsSTROBE__delay_us(100);PORTB = (PORTB & 0xF0) | (c & 0x0F); // send bottom 4 bitsSTROBE__delay_us(100);}void lcdputs(const char *s) // write a string to the LCD{RS = 1;while( *s )lcdwrite( *s++ );}void lcdwrite( unsigned char c ) // write one byte to LCD{PORTB = (PORTB & 0xF0) | (c >> 4);STROBE__delay_us(100);PORTB = (PORTB & 0xF0) | (c & 0x0F);STROBE__delay_us(100);}void lcdtop( unsigned char offset ) // set LCD to top line{unsigned char data; // define local variabledata = 0x80 | offset;RS = 0; // set LCD to COM modelcdwrite( data );}void lcdbot( unsigned char offset ) // set LCD to bottom line{unsigned char data; // define local variabledata = 0xC0 | offset;RS = 0; // set LCD to COM modelcdwrite( data );}void lcdclear( void ) // clear LCD and home cursor{RS = 0; // set LCD to COM modelcdwrite( 0x01 ); // write 01 to LCD__delay_ms(16); // wait for LCD to clear}void lcdinit( void ) // initialise the LCD{RS = 0; // set LCD to COM mode__delay_ms(15); // 15mS delayPORTB = 0x03;STROBE__delay_ms(5); // 5mS delaySTROBE__delay_ms(5);lcdwrite( 0x32 ); // set to 4 bit modelcdwrite( 0x2C ); // set for 2 lineslcdwrite( 0x08 ); // display offlcdwrite( 0x06 ); // set increment cursorlcdwrite( 0x0C ); // display on, cur offlcdwrite( 0x01 ); // clear display__delay_us(1600); // 1.6mS delaylcdwrite( 0x02 ); // home cur, clear RAM__delay_us(1600); // 1.6mS delay}/** File: main.c*/#define _XTAL_FREQ 4000000L// TODO: Add Configuration Bits here#include <xc.h>#include <stdio.h>#include "lcd.h"void main(void){float cap = 0.1;float res = 2489.0;float pi = 3.14159;float freq;int iFreq, iFrac;char outstring;ANSELB = 0;TRISB = 0; // set all PORTB bits as outputslcdinit();freq = 1.0 / ( 15.3906 * cap / 1000000 * res );iFreq = (int)freq;iFrac = (int)((freq - (float)iFreq) * 10.0 + 0.5);lcdtop( 0 ); // cursor to top line 1st charlcdputs( "Phase Shift Osc" );lcdbot( 0 ); // cursor to bottom line 1st charsprintf( outstring, "Freq = %d.%d Hz", iFreq, iFrac );lcdputs( outstring );// Main Loopwhile (1){}}Please use the "code" tags (i.e. the # button while writing a reply).

author: PerranOak
author_rank: Frequent Contributor
timestamp: May 12, 2020, 05:07:31 pm
content: Thanks all, I learned a lot from this thread.In the end, changing to C90 solved the whole thing.