Hi Mike,XC8 won't evaluate my constant expressions to a constant. That is, XC8 generates a whole bunch of bit-shift code for statements like this;
/*
* x_16f15325_oled.c excerpt (XC8 V2.00 build -1524193055)
*/
PMD4 = 1<<UART2MD | // UART2 module off
1<<UART1MD | // UART1 module off
1<<MSSP1MD | // MSSP1 module off
1<<CWG1MD; // CWG1 module off
LATA = 0x00; //
667 ;x_16f15325_oled.c: 266: PMD4 = 1<<UART2MD |;x_16f15325_oled.c: 267: 1<<UART1MD |;x_16f1
+ 5325_oled.c: 268: 1<<MSSP1MD |;x_16f15325_oled.c: 269: 1<<CWG1MD;
668 06FE 3001 movlw 1
669 06FF 00F5 movwf ??_main
670 0700 3000 movlw 0
671 0701 181A btfsc 26,0 ;volatile
672 0702 3001 movlw 1
673 0703 0A89 incf 9,f
674 0704 2F06 goto u134
675 0705 u135:
676 0705 35F5 lslf ??_main,f
677 0706 u134:
678 0706 0B89 decfsz 9,f
679 0707 2F05 goto u135
680 0708 3001 movlw 1
681 0709 00F6 movwf ??_main+1
682 070A 3000 movlw 0
683 070B 1A1A btfsc 26,4 ;volatile
684 070C 3001 movlw 1
685 070D 0A89 incf 9,f
686 070E 2F10 goto u144
687 070F u145:
688 070F 35F6 lslf ??_main+1,f
689 0710 u144:
690 0710 0B89 decfsz 9,f
691 0711 2F0F goto u145
692 0712 3001 movlw 1
693 0713 00F7 movwf ??_main+2
694 0714 3000 movlw 0
695 0715 1B1A btfsc 26,6 ;volatile
696 0716 3001 movlw 1
697 0717 0A89 incf 9,f
698 0718 2F1A goto u154
699 0719 u155:
700 0719 35F7 lslf ??_main+2,f
701 071A u154:
702 071A 0B89 decfsz 9,f
703 071B 2F19 goto u155
704 071C 3001 movlw 1
705 071D 00F8 movwf ??_main+3
706 071E 3000 movlw 0
707 071F 1B9A btfsc 26,7 ;volatile
708 0720 3001 movlw 1
709 0721 0A89 incf 9,f
710 0722 2F24 goto u164
711 0723 u165:
712 0723 35F8 lslf ??_main+3,f
713 0724 u164:
714 0724 0B89 decfsz 9,f
715 0725 2F23 goto u165
716 0726 0878 movf ??_main+3,w
717 0727 0477 iorwf ??_main+2,w
718 0728 0476 iorwf ??_main+1,w
719 0729 0475 iorwf ??_main,w
720 072A 009A movwf 26 ;volatile
721
722 ;x_16f15325_oled.c: 271: LATA = 0x00;
723 072B 0140 movlb 0 ; select bank0
724 072C 0198 clrf 24 ;volatile
/* *
* test a 10x14 font driver, switch to 'vertical' addressing mode *
* */
i2c_start(); // send I2C 'start'
i2c_write(0x78); // send I2C 'address'
i2c_write(0x00); // send SSD 'control' Co=0 D/C=0
i2c_write(0x20); // send SSD 'address mode" command
i2c_write(0x01); // send SSD 'vertical' mode param
i2c_write(OLED_SETCOLADDR); //
i2c_write(0); //
i2c_write(127); //
i2c_write(OLED_SETPAGEADDR); // set page (row) address
i2c_write(1); // start page (row) 1 (line 2)
i2c_write(2); // end page (row) 2 (line 3)
i2c_restart(); //
i2c_write(0x78); // send I2C 'address'
i2c_write(0x40); // send SSD 'control' Co=0 D/C=1
NVMADR = 0x1E00; //
i2c_write(0xFF); // left border line
i2c_write(0xFF); // "
i2c_write(0); i2c_write(0); // column 001
i2c_write(0); i2c_write(0); // column 002
i2c_write(0); i2c_write(0); // column 003
i2c_write(0); i2c_write(0); // column 004
do {
unsigned char count = 10; //
asm("fontlp: "); //
asm("movlb NVMCON1/128 "); // bank 16 |16
asm("bcf NVMCON1,6 "); // NVMREGS = 0 (not config) |16 <---
asm("bsf NVMCON1,0 "); // RD = 1 (initiate read) |16 <---
asm("incf NVMADRL,F "); // bump NVMADR |16
asm("lslf NVMDATL,W "); // |16
asm("call _i2c_write "); // |14
asm("movlb NVMDATL/128 "); // bank 16 |16
asm("rlf NVMDATH,W "); // |16
asm("call _i2c_write "); // |14
asm("decfsz main@count,F "); // |??
asm("bra fontlp "); // |??
i2c_write(0); i2c_write(0); // 2 blank lines between chars
i2c_write(0); i2c_write(0); // "
} while(NVMADRL < 100); //
i2c_write(0); i2c_write(0); // column 125
i2c_write(0); i2c_write(0); // column 126
i2c_write(0xFF); // right boarder line
i2c_write(0xFF); //
i2c_stop(); //
Well, I've only been using XC8 a short while so I'm still learning. Before XC8 I used BoostC for several years and it automatically supports bit access, such as "pmd4.uart1md = 1" or "pmd4 = 1<<uart1md", using the same constants that I would use in assembler. It seemed very clean and intuitive.
Cheerful regards, Mike
That works fine but it uses more memory so I did it the ugly way;Try pmd4bits.uart1md = 1 (include header for the requisite pic).
/************************************************************************
* *
************************************************************************/
void main()
{
PMD0 = 0<<_PMD0_SYSCMD_POSN | // Clock network 'on'
1<<_PMD0_FVRMD_POSN | // FVR module off
0<<_PMD0_NVMMD_POSN | // NVM module 'on'
1<<_PMD0_CLKRMD_POSN | // CLKR module off
1<<_PMD0_IOCMD_POSN; // IOC module off
PMD1 = 1<<_PMD1_NCOMD_POSN | // NCO module off
1<<_PMD1_TMR2MD_POSN | // TMR2 module off
1<<_PMD1_TMR1MD_POSN | // TMR1 module off
1<<_PMD1_TMR0MD_POSN; // TMR0 module off
PMD2 = 1<<_PMD2_DAC1MD_POSN | // DAC1 module off
1<<_PMD2_ADCMD_POSN | // ADC module off
1<<_PMD2_CMP2MD_POSN | // C2 module off
1<<_PMD2_CMP1MD_POSN | // C1 module off
1<<_PMD2_ZCDMD_POSN; // ZCD module off
PMD3 = 1<<_PMD3_PWM6MD_POSN | // PWM6 module off
1<<_PMD3_PWM5MD_POSN | // PWM5 module off
1<<_PMD3_PWM4MD_POSN | // PWM4 module off
1<<_PMD3_PWM3MD_POSN | // PWM3 module off
1<<_PMD3_CCP2MD_POSN | // CCP2 module off
1<<_PMD3_CCP1MD_POSN; // CCP1 module off
PMD4 = 1<<_PMD4_UART2MD_POSN | // UART2 module off
1<<_PMD4_UART1MD_POSN | // UART1 module off
1<<_PMD4_MSSP1MD_POSN | // MSSP1 module off
1<<_PMD4_CWG1MD_POSN; // CWG1 module off
PMD5 = 1<<_PMD5_CLC4MD_POSN | // CLC4 module off
1<<_PMD5_CLC3MD_POSN | // CLC3 module off
1<<_PMD5_CLC2MD_POSN | // CLC2 module off
1<<_PMD5_CLC1MD_POSN; // CLC1 module off
A perfectly valid and efficient way to do it. I used to do the same thing in asm and was criticized for writing bad code.That works fine but it uses more memory so I did it the ugly way;
Code:/************************************************************************ * * ************************************************************************/ void main() { PMD0 = 0<<_PMD0_SYSCMD_POSN | // Clock network 'on' 1<<_PMD0_FVRMD_POSN | // FVR module off 0<<_PMD0_NVMMD_POSN | // NVM module 'on' 1<<_PMD0_CLKRMD_POSN | // CLKR module off 1<<_PMD0_IOCMD_POSN; // IOC module off PMD1 = 1<<_PMD1_NCOMD_POSN | // NCO module off 1<<_PMD1_TMR2MD_POSN | // TMR2 module off 1<<_PMD1_TMR1MD_POSN | // TMR1 module off 1<<_PMD1_TMR0MD_POSN; // TMR0 module off PMD2 = 1<<_PMD2_DAC1MD_POSN | // DAC1 module off 1<<_PMD2_ADCMD_POSN | // ADC module off 1<<_PMD2_CMP2MD_POSN | // C2 module off 1<<_PMD2_CMP1MD_POSN | // C1 module off 1<<_PMD2_ZCDMD_POSN; // ZCD module off PMD3 = 1<<_PMD3_PWM6MD_POSN | // PWM6 module off 1<<_PMD3_PWM5MD_POSN | // PWM5 module off 1<<_PMD3_PWM4MD_POSN | // PWM4 module off 1<<_PMD3_PWM3MD_POSN | // PWM3 module off 1<<_PMD3_CCP2MD_POSN | // CCP2 module off 1<<_PMD3_CCP1MD_POSN; // CCP1 module off PMD4 = 1<<_PMD4_UART2MD_POSN | // UART2 module off 1<<_PMD4_UART1MD_POSN | // UART1 module off 1<<_PMD4_MSSP1MD_POSN | // MSSP1 module off 1<<_PMD4_CWG1MD_POSN; // CWG1 module off PMD5 = 1<<_PMD5_CLC4MD_POSN | // CLC4 module off 1<<_PMD5_CLC3MD_POSN | // CLC3 module off 1<<_PMD5_CLC2MD_POSN | // CLC2 module off 1<<_PMD5_CLC1MD_POSN; // CLC1 module off
OK, back to current consumption
I went on a short MicroChip course yesterday, about the new SAML10/11 ARM processors - part of which was specifically about low power consumption.
The development boards we were using actually include current monitoring, so you can check the consumption in specific modes. These chips are also 'officially' the lowest powered ones available, according to independent testing in real world conditions - the second best processor (another MicroChip product) only scores about half what this one does.
There's a ludicrous amount of power reducing facilities on the chip, including the capability of shutting down sections of RAM, and three different types of internal regulator for feeding the core.
We were running at 8MHz, and active mode was about 200uA - spec is 25.3uA/MHz - so pretty spot on.
Anyway, Idle mode didn't impress me greatly, only dropping it to about 120uA - but I've never really considered idle mode for what I'm doing anyway - spec is 15.2uA/MHz.
But 'proper' sleep dropped it to around 400nA - this is highly dependent on temperature, and is listed as 500nA at 25C.
There's also a fairly stupid 'off' mode, not really a sleep mode at all - and this reduces the power to 40nA - but you need a hardware reset to start it back up. I suppose it saves you needing to add hardware to actually switch the power off to the chip?.
So pretty impressive devices, and cheap as well (£1.74 from RS) - but pretty complicated as well - if you think modern PIC's have too many clock options, these are even worse
Hey Nigel, making your choice from the somewhat overwelming list of options could be complicate but once done the micro looks more or less like the "old" ones, isn't it?
Yup, the newer 16F devices are super flexible in pin arrangement. I use all those as well, though what are "bi-directional interrupts"?
I use interrupt on-change but can't see why throwing an interrupt if the PIC changes the value is useful. Maybe if a peripheral changes the output but usually they have there own interrupts....
I prefer to do debounce in software. This way you can use the internal pullups and turn them off when not needed.
You only need to turn on the pullups when you read the port. No need for any delays, you just poll the pin 20-50 times a second.
Mike.
...the pic woke 20 times a second to check a pin and then went back to sleep....
Mike.
I still have the prototype hanging around. It's probably about a year since it was last charged and it still works fine. It is however a 1Ah Lipo battery powering it.That's sure not quality sleep!
The pic will still wake from sleep without the hardware debounce but you will need a high value pullup - probably more efficient with a pulldown(?). One project I did, the pic woke 20 times a second to check a pin and then went back to sleep.
Mike.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?