View previous topic :: View next topic |
Author |
Message |
newguy
Joined: 24 Jun 2004 Posts: 1908
|
[SOLVED] PIC16LF18445, NVM PMD Affecting UART |
Posted: Wed Oct 28, 2020 1:21 pm |
|
|
Took me a while to diagnose the cause of a weird issue I was seeing. I'm at the point now where I'm not sure if it's the compiler or if it's an undocumented errata on the processor. Long story short, disabling the non-volatile memory via its peripheral module disable (PMD) bit ends up causing issues with the UART.
Project has a PIC16LF18445 processor. First program after I soldered the prototype was a bog standard flash an LED at a set rate. That worked. Moved on to testing the serial connection to the outside world and that's where I've sat for way too long. I've managed to diagnose the cause but I have no idea why. Stripped down test program that demonstrates the problem follows.
Compiler version 5.093
Code: | #include <16LF18445.h>
#device ADC=12
#FUSES NOEXTOSC //External Oscillator not enabled
#FUSES RSTOSC_HFINTRC //On Power-up clock running from HFINTRC
#FUSES NOCLKOUT //I/O function on OSC2
#FUSES NOCKS //Clock Switching Disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES MCLR //Master Clear pin enabled
#FUSES PUT_64MS //Power-Up timer set to 64ms
#FUSES NOLPBOR //Low-Power Brownout reset is disabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES ZCDDIS //Zero-cross detect circuit is disabled at POR
#FUSES PPS1WAY //Allows only one reconfiguration of peripheral pins
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES WRTD //Data EEPROM write protected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES PROTECT //Code protected from reads
#use delay(internal=4000000)
#pin_select U1TX = PIN_C6
#pin_select U1RX = PIN_C7
#use rs232(baud=57600, UART1, errors, STREAM=CONFIG)
#case
#use fast_io(C)
#byte PMD0 = getenv("SFR:PMD0")
#define PMD0_NVM_DISABLED 0x04
#define DEBUG_LED_PIN (PIN_A4)
#define DEBUG_LED_ON() (output_low(DEBUG_LED_PIN))
#define DEBUG_LED_OFF() (output_high(DEBUG_LED_PIN))
void main(void) {
output_c(0x40);
set_tris_c(0x80);
// general delay to allow everything to stabilize
delay_ms(250);
// flash the LED
DEBUG_LED_ON();
delay_ms(100);
DEBUG_LED_OFF();
PMD0 = PMD0_NVM_DISABLED; // this line causes the UART to stop transmitting***
// comment out above line and PIC transmits "Ready\r\n" every 100ms
while(TRUE) {
output_toggle(PIN_A4);
fprintf(CONFIG, "Ready\r\n");
delay_ms(100);
}
} |
During my diagnosis/troubleshooting of this issue I found that if the total number of characters I attempt to transmit is 3 or less, the UART actually keeps transmitting even if the non-volatile memory module is disabled per the line above. That was a fun one to diagnose. In all cases, the LED flashes at a 5Hz rate whether the UART actually transmits or not. Verified that the PIC's TX line sticks high with an oscilloscope when the issue manifests.
Relevant bit from the list file:
Code: | .................... PMD0 = PMD0_NVM_DISABLED; // this line causes the UART to stop transmitting***
00B4: MOVLW 04
00B5: MOVLB 0F
00B6: MOVWF PMD0 |
I'm unfamiliar with the memory mapping of this processor, so I'm unsure if the proper bank is being selected. The data sheet shows that PMD0 is at offset 0x0796 but I have no idea how that maps to a particular bank, nor if bank F is correct.
Any help would be appreciated. This is a very low power battery operated device; that's why I have to directly power down modules that aren't used.
Last edited by newguy on Thu Oct 29, 2020 10:55 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Oct 29, 2020 2:37 am |
|
|
The code uses PFM reads, to read things like the string "Ready\r\n".
This is why PFM reads must not be turned off in the config registers.
Disabling the NVM bit, prevents read access. Hence the code is
unable to read the string once this bit is set....
Quote: |
NVMMD
All Memory reading and writing is disabled; NVMCON registers cannot be
written; FSR access to these locations returns zero.
|
Code: |
#include <16LF18445.h>
#device ADC=12
#FUSES NOEXTOSC //External Oscillator not enabled
#FUSES RSTOSC_HFINTRC //On Power-up clock running from HFINTRC
#FUSES NOCLKOUT //I/O function on OSC2
#FUSES NOCKS //Clock Switching Disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES MCLR //Master Clear pin enabled
#FUSES PUT_64MS //Power-Up timer set to 64ms
#FUSES NOLPBOR //Low-Power Brownout reset is disabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES ZCDDIS //Zero-cross detect circuit is disabled at POR
#FUSES PPS1WAY //Allows only one reconfiguration of peripheral pins
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES WRTD //Data EEPROM write protected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES PROTECT //Code protected from reads
#use delay(internal=4000000)
#pin_select U1TX = PIN_C6
#pin_select U1RX = PIN_C7
#use rs232(baud=57600, UART1, errors, STREAM=CONFIG)
#case
#use fast_io(C)
#byte PMD0 = getenv("SFR:PMD0")
#define PMD0_NVM_DISABLED 0x04
#define DEBUG_LED_PIN (PIN_A4)
#define DEBUG_LED_ON() (output_low(DEBUG_LED_PIN))
#define DEBUG_LED_OFF() (output_high(DEBUG_LED_PIN))
void main(void) {
char temp_str[20]; //ram buffer
int ccnt;
output_c(0x40);
set_tris_c(0x80);
// general delay to allow everything to stabilize
delay_ms(250);
sprintf(temp_str, "Ready\r\n");
//put the message into RAM
// flash the LED
DEBUG_LED_ON();
delay_ms(100);
DEBUG_LED_OFF();
PMD0 = PMD0_NVM_DISABLED; // this line causes the UART to stop transmitting***
// comment out above line and PIC transmits "Ready\r\n" every 100ms
while(TRUE) {
output_toggle(PIN_A4);
for (ccnt=0;ccnt<strlen(temp_str);ccnt++)
fputc(CONFIG, temp_str[ccnt]); //print from RAM
delay_ms(100);
}
}
|
Shows a potential way to 'pregenerate' the output string in RAM, and
send this.
The read returning zero, means that the printf, won't output anything,
so no UART writes will occur.... So it is not the 'UART' being affected,
but the ability to read from the program memory to retrieve what is
to be sent.... |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Thu Oct 29, 2020 9:06 am |
|
|
Thanks Ttelmah. A clear case of not reading the data sheet to be sure. I had done several equivalent projects (battery powered, very low current draw) but with an 18 series PIC, and disabling the NVM on that chip disabled the EEPROM only. I was expecting similar behaviour. What really threw me was the fact that strings with lengths of 1, 2 or 3 characters would successfully be sent. Why that worked at all given that they shouldn't ever have worked is beyond me. I suppose I should dust off my Microchip support login and let them know about this weirdness. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Oct 29, 2020 9:33 am |
|
|
CCS doesn't bother to add the NVM access code for single characters,
or very short strings. They instead hard code the bytes. The access
costs quite a few bytes of program size, so not worth it for just a couple of
characters.
It's not really an oddity. It is doing what it says. You turn off the section
that allows access to NVM. If you then try to read the NVM, don't
be surprised if it doesn't work!... |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Thu Oct 29, 2020 9:55 am |
|
|
I'm now wondering if the "working" 18-series projects I've done before where I also disabled the NVM unless I was reading/writing the internal EEPROM weren't actually supposed to work at all....
...In those, code flow was identical; plenty of hard-coded strings being sent via the UART, and those projects functioned correctly. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Oct 29, 2020 10:32 am |
|
|
I suspect you are talking a different NVM access restriction.
If you look the NVM restriction created by the _protection_ system, turns
off the access from a programmer, not from the code. Hence the code
access keeps working.
Turning off the NVM read hardware is not possible on most chips. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Thu Oct 29, 2020 10:55 am |
|
|
It's simply a matter of me not reading the data sheet because I assumed it was going to have the same behaviour as an 18-series processor I had dealt with before. This processor's additional restriction on not being able to read program flash (i.e. ROM strings stored therein) when the NVM's PMD has been activated is not something I anticipated. I assumed that only the EEPROM would be deactivated.
Going back to the 18-series for a moment - I suppose that Microchip's nomenclature could have been more specific. On that processor they called the EEPROM disable "non-volatile memory (NVM)" but EEPROM would have been more appropriate. For this processor, NVM is entirely appropriate because it does "kill" read access to pretty much everything - but I assumed it was just going to restrict accesses to only the EEPROM, since that's what the PMD of the same name did on the 18 I was used to.
At any rate, problem averted thanks to your generous help/guidance (as always)! I'll edit the title to add [SOLVED]. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Oct 30, 2020 1:59 am |
|
|
Yes, makes total sense.
They are all 'parts' of the NVM, and the PMD function disables it all, while
the protection functions have options to disable it only for external
programmer or for the EEPROM only. It would make a lot more sense
to use the names defining what parts are affected... |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Fri Oct 30, 2020 8:08 am |
|
|
Just did one last check. The 18-series project I've mentioned that worked despite a similar program structure had one key difference:
Code: | #device PASS_STRINGS=IN_RAM |
I just added that to the PIC16 program above and it didn't make any difference. I thought that one line might have been why the 18 program worked but this one didn't, but that's not the case. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Oct 30, 2020 8:32 am |
|
|
No, The Pass_strings option means a temporary buffer is used, but the
data still has to be read from the program memory.
What chip were you using?. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Fri Oct 30, 2020 8:52 am |
|
|
18LF26K40 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Oct 30, 2020 9:31 am |
|
|
I suspect if you look at the assembler, the PIC18 does the read access using
an index register, rather than the NVM registers. The PIC18 there has table
read instructions supporting this. The PIC16 doesn't.... |
|
|
|