Jump to content

John P

EstablishedMember
  • Content count

    17
  • Joined

  • Last visited

Community Reputation

0 Neutral

About John P

  • Rank
    Newbrie
  1. I use a Lenovo B575 which cost a magnificent $300 in 2011, but last year I spent $200 to replace the motherboard (dubious economy there, but I didn't want the hassle of shifting everything over to a new machine--the hard drive was OK, so no issues concerning lost data). Boostc runs way slower than other compilers, and I'm just used to it being the way it is. Most of my programs are pretty small, anyway. By comparison, MikroC is almost instantaneous. I don't think it has much to do with the machine you run it on.
  2. It does say: @ 912: MESSAGE: "Warning: ICD2 Reserved ROM address range:0x1F00-0x1FFF (use linker -rt option)" I don't use ICD2, so I don't know how to interpret this. Is it a likely cause of the program not compiling? You could try removing the #include line temporarily, and see if it compiles OK then.
  3. It isn't necessary to "debounce" a switch at all, as long as you don't read it too frequently or allow it to create an interrupt. You just have to make sure that you poll the switch input bit(s) at some interval that's longer than the bounce time. If you don't need extremely fast response, 50msec is pretty generous. So you set up a timer to give a repeated overflow, which you can respond to either in an interrupt, if you already have one running at some fixed rate, or if your main() routine features an endless loop, you can just poll the overflow flag there, as long as you clear it once it's found to be set. You might or might not need to compare a "State now" with a "Last state" to detect new switch press/release events.
  4. I need to make an addition to the message I posted last month. Yes, you can subsitute your own code for the Boostc interrupt function. But if you do, you can't do it the way I showed. Where I failed was using local variables in my function, and when I thought about it (prompted by mysterious bugs) I realized that it had to be a mistake. The issue is that to the compiler, that block of code is just a function called from main(), and its local variables only have to be selected so as not to interfere with variables in use by main(). But in fact it's an interrupt which can be executed from anywhere, so any local variables used by any subroutines in the entire program (unless you have interrupts turned off) may confict with the variables in the interrupt. The only solution is to declare all the variables used by the interrupt either global or static. Not only this, but you have to inspect the disassembly file to see if the compiler has used scratchpad locations, and if there are any, you must re-write the code to cause them to go away, or else you have to save them at the start of the interrupt and then restore them. This is for the same reason as the elimination of local variables--the same memory bytes may be used elsewhere in the program. And although I didn't forget to do it, I didn't say it here--of course, any interrupt must end with a RETFIE instruction. So it's a technique that can work, but there are pitfalls along the way.
  5. Just dealing with that last question, yes it's possible to do this and I just figured it out for a program I've been working on. What you do is to avoid telling the compiler that you have an interrupt, but locate your code at address 0x0004. If interrupts are enabled, we know that the PIC jumps to address 4, so anything that you've placed there will be executed. Here's a section of my program that contains the start of the interrupt, and you can see I've commented out the original "interrupt" designation and replaced it with my own function name called "rupt()". Note that you do have to call "rupt()" from somewhere, or it will look like dead code and won't compile, and obviously that call must be from a place in your program that won't actually execute. I always do a typedef so "byte" is an unsigned char. void rupt(void)@4 //void interrupt(void) // Interrupt from TMR1 only { byte i, mask; byte fsr_sav, sta_sav; byte w_sav@0x7F; asm { MOVWF _w_sav SWAPF _status, W // BCF _status, 0x05 // Comment out because compiler // BCF _status, 0x06 // adds these lines automatically MOVWF _sta_sav } fsr_sav = fsr; bit_clear(pir1, TMR1IF); // Clear this interrupt's flag, no need to test because TMR1 is the only one
  6. John P

    Can't Use Computed Goto

    OK, thank you for taking an interest. Here is the routine in which I'm having the problem, and a 1-line main() function which calls this routine and does nothing else. Please understand that this version is made to compile but not run! It's for the PIC16F690 and I have version 7.20 of the compiler. What I'm seeing is first, if the asm{} construction isn't used with my list of GOTOs, they don't compile. If I do use asm{}, it compiles but it's very inefficient in terms of the amount of code produced, and time to execute. What I think is wrong is that the number of sequences of BCF 0x3, 0x5 and BCF 0x3, 0x6 is hugely excessive--it seems to happen before any variable is accessed. Surely the compiler could be made to figure out which bank is in use so it wouldn't need to keep selecting bank 0! If you want some background, what this routine does is send a data packet over a UART. It's a state machine which steps through the packet and sends a byte (or at the end, turns off the line driver) via a function call for each successive state, incrementing a counter each time. There are two packet types, and they're selected by starting the routine with the counter having the value 0 or 0x10. I don't like BoostC's way of implementing a Switch-Case construction, as that takes a highly variable amount of time to execute--less for the small numbers and more for the larger ones. I'd rather have the option to create a true computed GOTO, and if necessary I'll take the responsibility to make sure that the jump table stays in the same block of ROM. #include // device dependent interrupt definitions // Processor is PIC16F690 #define bit_set set_bit #define bit_clear clear_bit #define bit_test test_bit #define RESET_POWER 1 #define MY_ID 246 #define GOT_STATUSREQ 243 #define NORMAL 0x15 // Normal is 0x15 for a cab driver #define PACKET_START 0xFF #define C_D_TYPE 3 typedef unsigned char byte; byte button10, pot10, button11, pot11; // Used in send_to_server() byte packet_out_count; byte cs, outgoing; byte uptime[4]; /**************************************************************************** Sending data to server ****************************************************************************/ void send_to_server(void) { byte i; if (bit_test(packet_out_count, 7)) // 0xFF has appeared as data, send second time { txreg = PACKET_START; bit_clear(packet_out_count, 7); return; } if (packet_out_count > 0x1A) goto POC10; // Illegal count, cancel any packet in progress i = packet_out_count++; pcl += i; asm { // Jump table must fit within 256 byte block of addresses goto POC0; goto POC1; goto POC2; goto POC3; goto POC4; goto POC5; goto POC6; goto POC7; goto POC8; // Send checksum goto POC9; // Wait till complete, then release bus goto POC10; goto POC10; goto POC10; // P_O_C shouldn't have values 11-15 goto POC10; goto POC10; goto POC10; goto POC0x10; // Start packet goto POC0x11; goto POC2; // Send ID goto POC0x13; goto POC0x14; goto POC0x15; goto POC0x16; goto POC0x17; goto POC0x18; goto POC0x19; goto POC8; // Send checksum } POC0: txreg = PACKET_START; return; POC1: txreg = cs = NORMAL; return; POC2: txreg = MY_ID; cs += MY_ID; return; POC3: txreg = 4; cs += 4; return; POC4: txreg = pot10; cs += pot10; outgoing = (10 << 4) + button10; // Ensures that changes don't occur between bytes being sent bit_clear(pot10, 7); button10 = 0; return; POC5: txreg = outgoing; cs += outgoing; return; POC6: txreg = pot11; cs += pot11; bit_clear(pot11, 7); outgoing = (11 << 4) + button11; button11 = 1; return; POC7: txreg = outgoing; cs += outgoing; return; POC8: if (cs == PACKET_START) cs--; // Send 0xFE instead of 0xFF txreg = cs; return; POC9: if (!bit_test(txsta, TRMT)) // Has last byte completed transmission? packet_out_count--; // No, make sure we keep looking return; POC10: bit_clear(portc, 2); // Release bus to server (portc.2) bit_set(trisc, 3); // Release clamp TX line to USB converter return; POC0x10: txreg = 0xFF; return; POC0x11: // Cases 0x10 and up are for status request txreg = cs = GOT_STATUSREQ; return; POC0x13: txreg = 6; cs += 6; return; POC0x14: cs += C_D_TYPE; txreg = C_D_TYPE; return; POC0x15: cs += uptime[0]; txreg = uptime[0]; if (uptime[0] == PACKET_START) bit_set(packet_out_count, 7); return; POC0x16: cs += uptime[1]; txreg = uptime[1]; if (uptime[1] == PACKET_START) bit_set(packet_out_count, 7); return; POC0x17: cs += uptime[2]; txreg = uptime[2]; if (uptime[2] == PACKET_START) bit_set(packet_out_count, 7); return; POC0x18: cs += uptime[3]; txreg = uptime[3]; if (uptime[3] == PACKET_START) bit_set(packet_out_count, 7); return; POC0x19: cs += RESET_POWER; // Not fooling with any other kind of reset txreg = RESET_POWER; return; } main() { send_to_server(); }
  7. John P

    Can't Use Computed Goto

    I'm going to call this a bug, although it doesn't exactly cause failure. BoostC disdains to create a Switch-Case setup by manipulating the program counter. Instead it forces a long list of compare operations, which gets time-consuming if one of the last cases tests true. So I tried to write my own version, like this (I'm only showing the first 3 cases): i = packet_out_count++; pcl += i; asm { // Jump table must fit within 256 byte block of addresses goto POC0; goto POC1; goto POC2; goto POC3; goto POC4; goto POC5; goto POC6; goto POC7; goto POC8; // Send checksum goto POC9; // Wait till complete, then release bus return; return; // P_O_C shouldn't have values 10-15 return; return; return; return; goto POC0; // Start packet goto POC0x11; goto POC2; // Send ID goto POC0x13; goto POC0x14; goto POC0x15; goto POC0x16; goto POC0x17; goto POC0x18; goto POC0x19; goto POC8; // Send checksum } POC0: txreg = 0xFF; return; POC1: txreg = cs = NORMAL; return; POC2: txreg = MY_ID; cs += MY_ID; return; POC3: txreg = 4; cs += 4; return; Apparently this only works if the list of GOTOs is in an asm{} construction, because otherwise the compiler assumes that only the first GOTO is accessible, and won't produce code for any of the others. In the asm{} setup, the code is generated, but then when the individual cases are reached, they produce highly inefficient code, like this (from the Disassembly Listing): 278: POC0: 279: txreg = 0xFF; 064 30FF MOVLW 0xff 065 0099 MOVWF 0x19 280: return; 281: POC1: 282: txreg = cs = NORMAL; 067 3015 MOVLW 0x15 068 1283 BCF 0x3, 0x5 069 1303 BCF 0x3, 0x6 06A 00CB MOVWF 0x4b 06B 1283 BCF 0x3, 0x5 06C 1303 BCF 0x3, 0x6 06D 0099 MOVWF 0x19 283: return; 284: POC2: 285: txreg = MY_ID; 06F 30F6 MOVLW 0xf6 070 1283 BCF 0x3, 0x5 071 1303 BCF 0x3, 0x6 072 0099 MOVWF 0x19 286: cs += MY_ID; 073 30F6 MOVLW 0xf6 074 1283 BCF 0x3, 0x5 075 1303 BCF 0x3, 0x6 076 07CB ADDWF 0x4b, F 287: return; You can see that there is a lot of totally unnecessary clearing of bits of the status register, every time a variable is used. It looks to me as if the compiler is punishing me for trying to use a work-around for something it didn't want to do! Surely this isn't intentional.
  8. Thanks for the reply, Jorge--I don't think I'd ever have noticed that little switch. I could try writing some experimental code and see if it handles it differently. Then I'd have to see if my Pickit2 programmer will work with the processor; it's not on the list of supported parts. Edited to say that yes, the PicKit2 will do this if you have the right file of parts for it.
  9. I haven't tried this, but maybe someone here knows. The PIC16F1824/1828 has some added features compared to most other 16F parts. It has 2 File Select Registers (FSR, location 0x4) and it can do indexed jumps, not just skip a single line, and various other new things. There are added instructions (49 available, versus 35) to control the new features. Does BoostC produce code for optimum use of the new hardware and software possibilities, or will it just treat the 16f1824/16F1228 like an older equivalent?
  10. That last suggestion shows some lack of knowledge about how code for microcontrollers is used. Here we are on a discussion forum about a compiler; I don't object to compilers! The advantages to using one are too obvious to be worth discussing. On the other hand, there are times when part (just part!) of one's code needs to run at the highest speed, or needs to run at some speed that's predictable on the basis of how the program was written, on a finer scale than you could ever get simply using an interrupt. That's when the user would consider using a brief section of assembly, and then it's intolerable to have the compiler inserting "helpful" extra lines. For the time that I'm using assembly, I want full control of what's in the code. As you see in my code snippet, I'm controlling an external port. I'm using it to bit-bang an external circuit, and I want control over the timing. Is that too much to ask? Well, I've fired up my many-versions-obsolete CCS compiler and it still works fine. I had to lie to it about which processor I'm using and define a whole lot of registers, but fortunately, with the 16F PICs, the code is always the same.
  11. I wrote some of my program in assembly for the reason that people usually do--to get completely optimized code where I'd know exactly how long everything will take. So here's a line of C code that I rewrote into assembly: MOVLW 0x40 // portb = 0b01000000; MOVWF _portb Now when I compile/assemble the program, I find that the compiler insists on setting the register bank to zero. Doing this adds two extra instructions! And the wasted lines are added again and again, just in case I sneaked a bank change in when the compiler wasn't looking. Like this, in the "View Disassembly Listing": 117: MOVLW 0x40 // portb = 0b01000000; 054 3040 MOVLW 0x40 118: MOVWF _portb 055 1283 BCF 0x3, 0x5 056 1303 BCF 0x3, 0x6 057 0086 MOVWF 0x6 I'd have thought that if I'm willing to use assembly, it's my responsibility to set the bank. Or at least, there should be a command to lock out helpful behavior by the compiler. But I'm not encouraged by the manual, where it says "Bank switching and code page switching code should NOT be added to inline assembly code. The linker will add the appropriate Bank switching and code page switching code." If there were a way to stop it happening, wouldn't this be the place to tell the user? This isn't a positive feature, in my humble opinion.
  12. I'll stick with the assembly language block then. And thanks for the reminder about fixing the function address. That's definitely needed with the way I've written this.
  13. Hi Dave. Thanks for the prompt response. I did download 7.11, and I was all set to report back that it didn't make any difference. But it's more interesting than that. It still won't compile my block of GOTO's. But then I tried a workaround that failed with the previous version (I have 7.05). And that seems likely to work. What I did was take some of the jump table and put it in an asm{} block, like this: bit_set(porta, 1); // A flag for the scope, to see how long this takes pclath = 1; pcl += bitc; // Computed GOTO: jump 0-179 lines ahead // NOTE! This jump table must not span a location in code memory where the lower 8 address bits wrap from 0xFF to 0x00 // Also, PCLATH must hold the correct value for the memory area being used. asm{ GOTO SW0 GOTO INCU goto SW2 goto QX } goto SW0; // Start bit, start char goto INCU; goto SW2; goto QX; With 7.05, this fails with "Internal Error: Unable to resolve label ID:268436043 - 0x1000024B failure BUILD SUCCEEDED: Sun Nov 25 11:18:23 2012" Why it says "failure" followed by "BUILD SUCCEEDED" is probably not worth pursuing. But with 7.11, it produces code, as seen in the disassembly listing (and you can also see that the GOTO's that aren't in the asm{} block produce no code): 497: bit_set(porta, 1); // A flag for the scope, to see how long this takes 0242 1485 BSF 0x5, 0x1 498: pclath = 1; 0243 3001 MOVLW 0x1 0244 008A MOVWF 0xa 499: pcl += bitc; // Computed GOTO: jump 0-179 lines ahead 0245 0866 MOVF 0x66, W 0246 0782 ADDWF 0x2, F 500: // NOTE! This jump table must not span a location in code memory where the lower 8 address bits wrap from 0xFF to 0x00. 501: // Also, PCLATH must hold the correct value for the memory area being used. 502: asm{ 503: GOTO SW0 0247 2A4B GOTO 0x24b 504: GOTO INCU 0248 2AA0 GOTO 0x2a0 505: goto SW2 0249 2A53 GOTO 0x253 506: goto QX 507: } 024A 2ABA GOTO 0x2ba 508: 509: goto SW0; // Start bit, start char 510: goto INCU; 511: goto SW2; 512: goto QX;
  14. I'm trying to convert a program from another compiler, and I have got it to compile under BoostC. But the program includes a jump table which is entered after the PCL is changed--a computed GOTO in other words. What I'm finding is that the compiler simply generates no code for any of the GOTO statements, then it resumes at the next address after the last GOTO. Here are the last few lines before the table and the first few lines of the table: bit_set(porta, 1); // A flag for the scope, to see how long this takes pclath = 1; pcl += bitc; // Computed GOTO: jump 0-179 lines ahead // NOTE! This jump table must not span a location in code memory where the lower 8 address bits wrap from 0xFF to 0x00. // Also, PCLATH must hold the correct value for the memory area being used. goto SW0; // Start bit, start char goto INCU; goto SW2; goto QX; goto SW2; goto QX; goto SW2; // Many more GOTO's here Any ideas on how to make the compiler accept this?
×