PIC16F18325 - Pin voltage shows 2.8V with internal weak pull up enabled and not 5V - pic

I'm trying to configure all pins of PORTA in PIC16F18325 as input pins. I've disabled analog, configured the tristate TRISA register as inputs, setting open drain register - ODCONA to push-pull as well as open drain configuration, and also tried the combinations as mentioned in the data sheet. However, i'm facing a problem that when the pin is configured as an input, it never reaches 5V even when weak pull up enabled.
It always stays at 2.8v.
What makes it more worse and confusing is - with the same settings for PORTA and PORTC - some of the pins of both ports - PORTA and PORTC read 2.8V and some read 4.0V.
However, configuring PORTA as output, and toggling the outputs generates 0V and 5V when it changes the state.
Struggling from few days, checked out in microchip forums as well, but no results to find, especially for this chip - PIC16F18325. Any experts who can shed some light / thoughts?
I've also tried using the mcc for code configuration.
Disabling brown out reset also. There also same result and no luck.
Below is my complete main.c file.
// PIC16F18325 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits (HFINTOSC (1MHz))
#pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; I/O or oscillator function on OSC2)
#pragma config CSWEN = OFF // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config WDTE = OFF // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)
#pragma config LPBOREN = OFF // Low-power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled)
#pragma config BORV = LOW // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)
#pragma config PPS1WAY = OFF // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence))
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will not cause a Reset)
#pragma config DEBUG = OFF // Debugger enable bit (Background debugger disabled)
// CONFIG3
#pragma config WRT = OFF // User NVM self-write protection bits (Write protection off)
#pragma config LVP = OFF // Low Voltage Programming Enable bit (High Voltage on MCLR/VPP must be used for programming.)
// CONFIG4
#pragma config CP = OFF // User NVM Program Memory Code Protection bit (User NVM code protection disabled)
#pragma config CPD = OFF // Data NVM Memory Code Protection bit (Data NVM code protection disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 4000000
#include <xc.h>
void main(void)
{
//DISABLE ANALOG INPUTS
ANSELA = 0x00;
//PORTA PINS ARE INPUTS
TRISA = 0xFF;
//DISABLE OPEN DRAIN CONTROL ON PORTA
ODCONA = 0x00;
//ENABLE WEAK PULL UP ON ALL PORTA BITS
WPUA = 0xFF;
//TRIED BOTH - 0XFF and 0X00;
INLVLA = 0x00;
//DISABLE ALL MULTIPLEXED DEVICES CONNECTED TO PORTA JUST IN CASE THEY ARE CREATING ANY ISSUES
CM1CON0bits.C1ON = 0;
CM2CON0bits.C2ON = 0;
DACCON0bits.DAC1EN = 0;
SSPCON1bits.SSPEN = 0;
while (1)
{
// Add your application code
__delay_ms(100);
}
}
Any thoughts? TIA
It is all of PORTA bits, and not just RA0,RA1.
Have tried removing the ICSP header before itself, but did not show any difference. The output of 2.8V is on RA0,RA1 and RA2 pins.
I'm using FLUKE multimeter to test the voltage. Other multimeter also shows the same.
Configuring the same to PORTC pins have same result. RC1,2,3 have 2.8V, and RC4,5 have 4.0V. When I configure PORTC as output and toggle them, I get 0V and 5V.
No devices / nothing connected on any pins of PORTA or PORTC. Just VCC/GND on pins 1 and 8 respectively. MCLR (pin4) is connected to VCC via 10K resistor.

You have left out perhaps the single most important bit of information from your question, that is: What specific pin or pins of PORTA have been measured at 2.8 volts.
If it's just RA0 and RA1 the answer is that you still have the device programmer connected.
The In-Circuit-Serial-Progammers have pull-down resistors on the PGD/PGC lines.
If it's all of PORTA then what do you actually have connected to the port?
Or as GJ suggest are you using a real crap volt meter?
EDIT 1
I looked into the PIC16F18325 data sheet for the pull-up current specification for the weak pull-up function. This is what it shows:
At a minimum pull up current of 25uA the resistance to ground for a 2.8 volt drop is at most 112k ohms.
It's possible that your controller is outside of its specifications.
As a sanity check you may want to measure the input resistance of your volt meter to be certain it is more than 1meg ohm when measuring volts.
EDIT 2
I do not have a PIC16F18325 handy but I do have its bigger cousin the PIC16F18877. The same kind of weak pull-up are implemented in this silicon.
I have tested this controller and all the weak pull-up work as expected.
Suggest that you isolate the PORTA pin that you are measuring 2.8 volts on from your circuit. If you are using the DIP package bend it to just hang out in the air and then measure the pin voltage.
I suggest this because I got all excited that I had replicated you problem but I was wrong. I did my tests using the PICDEM2 plus (DM163022 no longer available) and RA1 behaves just as you described.
It turns out that the latest version (the one I have) connects RA1 to a voltage divider used to sense the battery/DC power input. Removing J12 got RA1 to work correctly with the weak pull-up enabled.

Related

change PWM duty cycle from within ISR

I have little problems implementing a dither function to upgrade the PWM resolution of my ATmega88 and the leds it's controlling.
My thought was, to use a "kind of" floating number, consisting of two uint8_t as "decimal places" so that e.g. "255.31" would be represented by "0xff.0x1f" (BYTE_HIGH.BYTE_LOW).
Now I want the value in the OCR to dither between BYTE_HIGH and BYTE_HIGH+1 and for this I need a second counter (besides the timer itself) to generate an overlayed dutycycle (the duty cycle of the timer has to be incremented after (int) 255-BYTE_LOW cycles). But managing this stuff in the main() results in flicker and so I'd like to do this in an ISR called on timer overflow.
My avr is running at 20 MHz and to get a sufficient dither frequency I cannot use a prescaler higher than 8. Do you think, I might be calling the ISR too frequently? But there is not too much code in the ISR, though.
Another problem I could think of is, that the ISR has to write the OCR which might be read by the timer at the same time, but isn't this kind of "thread save" as the timer does never write to OCR?
I have not found anything concerning my problem appropriately and so I hope to get some hints. See my code below
#include <avr/interrupt.h>
#include <avr/io.h>
#define compare_register OCR2B //duty cycle
volatile uint8_t dither_count=0;
volatile uint8_t BYTE_HIGH=0;
volatile uint8_t BYTE_LOW=0;
void init_pwm(void){
//some standard pwm initializations
TCCR2A |= (1 << COM2A1);
TCCR2A |= (1 << COM2B1);
// non inverting, fast PWM mode and prescaler to
TCCR2A |= (0 << WGM21) | (1 << WGM20);
TCCR2B |= (1 << CS21);
// set desired pin as an output (not sure, if it's the correct pin, because I left out other pins in use)
DDRD = (1 << DDD3)|(1<<DDD4);
// enable interrupt on timer overflow
TIMSK2 |= (1<<TOIE2);
// enable global interrupts
sei();
}
ISR(TIMER2_OVF_vect){
dither_count++;
if(dither_count<=BYTE_LOW){
compare_register=BYTE_HIGH+1;
}else{
compare_register=BYTE_HIGH;
}
}
int main(){
init_pwm();
//this or any function dimming the leds
BYTE_HIGH=10;
BYTE_LOW=1;
}
This theoretically should work, but unfortunately it doesn't work in real. The ISR gets called, but does not act as desired. Do I call the variables correctly inside of the ISR?
I would be glad if someone would see a fundamental misstake I did, especially because I do not have any serial interface working for debugging...
Edit: meanwhile I found out, that obiously the ISR gets stuck and will block any code executed in my main function...
I tried your program on an Arduino Uno. This board is based on a
ATmega328P which, save for some extra memory, is basically the same as
your Mega88 (same datasheet). I first added the following lines at the
end of main():
init_pwm();
// Blink the LED on PB5.
DDRB |= _BV(PB5);
for (;;) {
PINB |= _BV(PB5);
_delay_ms(400);
}
The first line is obviously needed for the PWM to work. The LED blinking
is just a test to see whether the program gets stuck in the ISR or not.
The result is: it does not. The LED blinks just as expected. The PWM
output looks also OK on the scope. Notice that, contrary to what the
comment in the code says, you are configuring the timer in phase
correct PWM mode, not in fast PWM. The timer period is then 2×255 timer
clock cycles instead of 256.
I disassembled the binary and tried to count the number of CPU cycles
needed to service the interrupt. With the program compiled at the -Os
optimization level, I got about 50. Given that the interrupt fires every
2×255×8 = 4080 cycles, that's about 1.2% of the CPU power
spent servicing the interrupt.

MPLAB xc8 pic16f688 pragma for WDTE Ignored

when using #pragma CONFIG = WDTE OFF
I get a message that:
WDTE is set to ON do I want it changed?
I do answer yes.
What concerns me is are other config statements ignored?
I can't tell. New to PIC.
Trying to make LED flash with PIC16F688.
I got it to work, kind of. I made sure the #pragma statements preceeded the #include and #define. What follows is the block of #pragma statements that did NOT work.
#pragma config WDTE = 0x0
#pragma config PWRTE = 0x0
#pragma config MCLRE = 0x0
#pragma config CP = 0x0
#pragma config CPD = 0x0
#pragma config BOREN = 0x1
#pragma config IESO = 0x1
#pragma config FCMEN =0x1
I went to the hex approach to avoid definitions of ON and OFF
I used MPBLAB's "set configration bits" under the RUN drop down to set the bits, changing them to hex. This still gave the WDTE, then the error vanished and I picked up a PWRTE CP error. I discovered I had set MCLRE to 1, so setting it to 0 it I still received the config error messages, but the program ran.
Then, I used only the statement #pragma config CONFIG 0xFF5. I got no config errors, but a warning that the 0xFF5 was going to automatically truncated to 0xFFF.
Now it all runs, but, I cannot get debug to run.
In now with that issue, which, I suppose is a different thread.
However the questions arises as to how the configuration word is formed, what bits contribute part of the word. I tried to guess from some registers but got nowhere. It would be nice to know.
Also, noting 0xFFF sets each bit in the word to 1 would imply that all my #pragma config statements (bits) = 1, which makes no sense.
I made my program and circuit run by using other troubleshooting methods. I would like to use debug in the future. I have read and re-read in PICkit 3 guide about PGD and PGC and having a clock running on the chip. My o'scope says I have a running clock (internal 4 MHZ). The PIC16F688 does not use the terminology PGD and PGC, but the pins are labeled ICSPDAT and ICSPCLK, respectively. Why debug does not work?
Sometimes people define OFF in a header file and break the pragma.
Actually every single time someone has asked me this question that was the case so I am 99% sure that this is your problem.
Never include any headers before the pragma !!!
The correct way is:
pragma config WDTE = OFF
pragma config PWRTE = OFF
....

What's the relationship between GPIO and SPI?

I found GPIO driver in the kernel leave /sys/class/gpio to control gpio, but I found GPIO can be controlled by /dev/mem as well, I found this mapping may be done in the spi-bcm2708 (which call the __ioremap as a platform driver), but I don't understand the relationship between spi and GPIO,how they work together in the linux?
As I understand you are talking about this driver (which is used, for example, in Raspberry Pi). First of all, take a look at BCM2835 datasheet. Review next sections:
1.1 Overview
6.0 General Purpose I/O (GPIO)
6.2 Alternative Functions Assignments (see Table 6-31)
From driver code (see bcm2708_init_pinmode() function) and datasheet (table 6-31), we can see that SPI pins are actually GPIO7..11 pins. Those pins can be actually connected to different hardware modules (either SPI or SD, in this case).
Such a selection is done using pin muxing. So basically you need to connect GPIO7..GPIO11 pins to SPI module. To do so you need to select ALT0 function for each of GPIO7..GPIO11 pins. This can be done by writing corresponding values to GPFSEL0 and GPFSEL1 registers (see tables 6-1..6-3 in datasheet):
And this is how the driver is actually doing this:
/*
* This function sets the ALT mode on the SPI pins so that we can use them with
* the SPI hardware.
*
* FIXME: This is a hack. Use pinmux / pinctrl.
*/
static void bcm2708_init_pinmode(void)
{
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define SET_GPIO_ALT(g, a) *(gpio+(((g)/10))) |= (((a) <= 3 ? (a)+4 : (a) == 4 ? 3 : 2)<<(((g)%10)*3))
int pin;
u32 *gpio = ioremap(GPIO_BASE, SZ_16K);
/* SPI is on GPIO 7..11 */
for (pin = 7; pin <= 11; pin++) {
INP_GPIO(pin); /* set mode to GPIO input first */
SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
}
iounmap(gpio);
#undef INP_GPIO
#undef SET_GPIO_ALT
}
which looks like quick hack to me, and they actually mentioned it: the correct way would be to use kernel mechanism called pinctrl.
Conclusion: BCM2708 driver doesn't actually trigger any GPIO pins, it's just doing pin muxing in order to connect GPIO7..GPIO11 pins to SPI module. And to do so this driver writes to GPFSELn registers, which happen to be GPIO registers. This is pretty much all relationship between SPI and GPIO in this driver.
P.S.: if you are curious about possible relationship between SPI and GPIO, read about bit banging. See for example spi-bitbang.c driver in Linux kernel.

UART RX Interrurpt fired too early

I'm doing a small project, where I want to transmit a text via a cable to my Atmega328p.
I first created the project on an Arduino Uno (with pure C), where the transmission works.
Now I switched to a standalone 328p and tried it there.
But now the Problem is, that my RX-Complete Interrupt is fired too early. In fact it is even fired, when nothing has been transmitted. It will fired when I just touched the cable (the isolated parts) .
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
void setup(void){
CLKPR = 0;
//Set Output
DDRC |= (1 << PC0) | (1 << PC1) |(1 << PC2) |(1 << PC3) |(1 << PC4) | (1 << PC5);
DDRD |= (1 << PD6) | (1 << PD7);
// Interrupts
sei();
// Init UART
// Set baud
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
// Enable UART Receive and Receivecomplete Interrupt
UCSR0B = (1<<RXEN0) | (1 << RXCIE0);
// Set frameformat to 8 Data and 1 Stopbit
UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));
}
int main(void){
setup();
while(1){
}
return 0;
}
ISR(USART_RX_vect){
// Enable some LEDs
}
Edit: Picture of my Setup:
I use the Arduiono just for Powering my Breadboard. 5V and GND are connected.
The AVR MKII ISP is Connected via some Pins to flash the µC. The two cables are used for UART RX.
The Pushbutton is just for RESET
Edit 2: I just tried to power it via an external source and a raspberrypi. There is the same effect everywhere
Of course. RXC flag is set when there are unread data in the receive buffer.
This flag is used to generate the RX interrupt.
Since you never read UDR inside your interrupt, this flag remains set, and, therefore just after interrupt routine is completed, it is starts again. And again. And again....
The Rx line should not be floating. Its a high impedance input and should be driven to a specific level. Your cables act like an antenna and if you touch the cable it gets worse because there is capacitive coupling between the cable and your body. This may result in high frequency noise on your input which may trigger the Rx interrupt.
Further make sure that the 328p local power supply is properly decoupled. I don't see any capacitors near the controller on your breadboard. Check GND connection between Arduino and 328p (mandatory).
Without looking at your setup it's hard to tell what's going wrong, but if you're touching an isolated cable and getting a response from the processor, then I would check common grounds between the devices if you're powering the ATMega via a battery, make sure the battery ground is touching the device that's receiving and transmitting, as any potential difference in power levels could cause the little magnetic field that you give off to be amplified into something that the core registers as a high bit.If possible, post a picture of your setup!
Also when programming with ATMel chips, burning the arduino bootloader and going the simple(r) C code way never hurt.

Turn an LED on or off in AT Mega-1284P Xplained

I am a beginner in AT Mega-1284P Xplained.
I want to turn an LED on and then off (say, LED0) after some specified time in AT Mega 1284P Xplained board from ATMEL. To my surprise, I found no official documentation for this rudimentary task but several different function calls - all of which failed compilation - searching on the web.
Please mention the API call as well as the header file that needs to be included for this. I am using AVR Studio 6.
I will assume a led is connected to pin 0 at port b on the AtMega1284P. The following program should make the led blink.
#include <util/delay.h>
#include <avr/io.h>
int main() {
// Set the pin 0 at port B as output
DDRB |= (1<<PB0);
while(1) {
// Turn led on by setting corresponding bit high in the PORTB register.
PORTB |= (1<<PB0);
_delay_ms(500);
// Turn led off by setting corresponding bit low in the PORTB register.
PORTB &= ~(1<<PB0);
_delay_ms(500);
}
}
Answering my own question: I found Atmel had an example code that covered a bunch of sensors and other peripheral components including LEDs for Mega-1284P. The links are link and link. Besides, very hard to find locations (they did not show up on web searches), the websites are _very_slow. Atmel, are you listening?

Resources