PWM settings in PIC24FJ64GA002 - microcontroller

Good day, I am working with a PIC24FJ64GA002 microcontroller and am struggling to get the PWM working for a servo I want to use. My code is as follows:
// PIC24FJ64GA002 Configuration Bit Settings
// 'C' source line config statements
// CONFIG2
#pragma config POSCMOD = NONE // Primary Oscillator Select (Primary oscillator disabled)
#pragma config I2C1SEL = PRI // I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = ON // IOLOCK Protection (Once IOLOCK is set, cannot be changed)
#pragma config OSCIOFNC = OFF // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as CLKO (FOSC/2))
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = FRC // Oscillator Select (Fast RC Oscillator (FRC))
#pragma config SOSCSEL = SOSC // Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG // Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = ON // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) enabled)
// CONFIG1
#pragma config WDTPS = PS32768 // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128 // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = ON // Watchdog Timer Window (Standard Watchdog Timer enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON // Watchdog Timer Enable (Watchdog Timer is enabled)
#pragma config ICS = PGx1 // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF // JTAG Port Enable (JTAG port is disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
/*
* File: 34660046LAB2.c
* Author: leone
*
* Created on 06 September 2021, 1:27 PM
*/
#include "p24FJ64GA002.h"
#include "xc.h"
#define _LATR15 OC1R
int main(void) {
T2CON = 0x8010;
TMR2=0;
PR2=9999;
_T2IP=4; //Default priority value
_T2IF=0; //Clears interrupt flag before interrupt
_T2IE=1; //Enables interrupt
OC1CONbits.OC = 0; // Output compare channel is disabled
OC1R = 0x1388 ; // Initialize Compare Register1 with 50% duty cycle
OC1CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC1CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC1CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC1CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
TRISBbits.TRISB15=0;
_LATB15=0;
while(1)
{
if(TMR2>OC1R)
{
_LATB15=1;
}
else
{
_LATB15=0;
}
}
return 0;
}
I programmed the T1CON to have a period of 2 ms, and the OC1R to have half that period, which should lead to a duty cycle of 50%. I am using the FRC oscillator (8MHz) and my pre-scaler values were <0,1>. I understand the it's the OC1R pin that gives the period the cycle is high, but in the datasheets they refer to it as a pin, however they don't give what pin it is (i.e. A0,A1,R15 etc.) There is also very little example code I could find explaining the how to code this well. If anyone is a PIC expert of some kind help would be very much appreciated! The datasheet for the MCU can be downloaded at https://www.microchip.com/en-us/product/PIC24FJ64GA002.

First of all configure the IO pins for PWM output, I assume you use SPDIP package and wanna use the OC1 PWM output pin:
// Unlock Registers
__builtin_write_OSCCONL(OSCCON & 0xBF);
// Configure Output Functions (Table 10-3)
// Assign OC1 To Pin RP2
RPOR1bits.RP2R = 18;
// Lock Registers
__builtin_write_OSCCONL(OSCCON | 0x40);
For the output pin configurations see the 10.4.3.2 Output Mapping section of the datasheet.
As per steps in the datasheet's 14.3 Pulse-Width Modulation Mode section:
Set the PWM period by writing to the selected Timery Period register (PRy). İf your period is 2 ms then compute the PRy register value:
#define Fosc ( 8000000 )
#define PWM_PERIOD_MS ( 2 )
#define PWM_FREQ_HZ ( 1000 / PWM_PERIOD_MS ) // In this case 500Hz
#define PRy_VALUE (uint16_t) ( (( Fosc ) / ( 4 * TMRyPS * PWM_FREQ)) - 1 )
// Somewhere in the init func or code assign the computed value for the period register
PRx = PRx_VALUE;
Set the PWM duty cycle by writing to the OCxRS register. Since you want a 50% duty cycle compute the value for OCxRS register:
#define DUTY (50)
#define DUTY_VALUE (uint16_t) ( ( 4 * ( TMRyPS - 1 ) * DUTY ) / 100 )
// Somewhere in the init func or code assign the computed value for the duty cycle register
OCxRS = DUTY_VALUE;
Write the OCxR register with the initial duty cycle. Assign the DUTY_VALUE to the OCxR register right after OCxRS assignment:
OCxR = DUTY_VALUE;
Enable interrupts, if required, for the timer and output compare modules. The output compare interrupt is required for PWM Fault pin utilization.
Configure the output compare module for one of two PWM Operation modes by writing to the Output Compare Mode bits, OCM<2:0>
(OCxCON<2:0>).
OC1CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC1CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
Set the TMRy prescale value and enable the time base by setting TON (TyCON<15>) = 1.
T2CON = 0x0010 // Timer2 prescaler 1:8, internal clock
T2CON.TON = 1;
From now on you should have the PWM working if the above steps are done correctly. Modify your code as per instructions here. Then try it and let me know the result.

This is a complete application that builds with MPLABX v5.50 and XC16 v1.70:
/*
* File: main.c
* Author: dan1138
* Target: PIC24FJ64GA002
* Compiler: XC16 v1.70
* IDE: MPLABX v5.50
*
* Created on October 8, 2021, 1:12 PM
*
* PIC24FJ64GA002
* +-------------------:_:-------------------+
* ICD_VPP --> : 1 MCLR VDD 28 : <-- 3v3
* < > : 2 RA0/AN0 VSS 27 : <-- GND
* < > : 3 RA1/AN1 AN9/RP15/RB15 26 : < >
* ICD_PGD < > : 4 RB0/PGD1/AN2 AN6/RP14/RB14 25 : < >
* ICD_PGC < > : 5 RB1/PGC1/AN3 AN7/RP13/RB13 24 : < >
* PWM/OC1 < > : 6 RB2/RP2/SDA2/AN4 AN8/RP12/RB12 23 : < >
* < > : 7 RB3/RP3/SCL2/AN5 RP11/RB11 22 : <*>
* - > : 8 VSS RP10/RB10 21 : <*>
* < > : 9 RA2/OSCI VCAP 20 : <-- 10uF
* < > : 10 RA3/OSCO VSS 19 : <-- GND
* < > : 11 RB4/RP4 SDA1/RP9/RB9 18 : <*>
* < > : 12 RA4 SCL1/RP8/RB8 17 : <*>
* 3v3 --> : 13 VDD RP7/RB7 16 : <*>
* <*> : 14 RB5/RP5/PGD3 PGC3/RP6/RB6 15 : <*>
* +-----------------------------------------+
* DIP-28
* * Indicates 5.0 volt tolerant input pins.
*
* Description:
* Initialize the controller to use a system oscillator of 8MHz from the on chip Fast RC oscillator.
* Setup the OC1 function to provide a 4KHz square wave output on GPIO pin RB2.
*
* Notes:
* See: https://stackoverflow.com/questions/69453833/pwm-settings-in-pic24fj64ga002
*
*/
#pragma config POSCMOD = NONE, I2C1SEL = PRI, IOL1WAY = OFF, OSCIOFNC = ON
#pragma config FCKSM = CSECMD, FNOSC = FRC, SOSCSEL = SOSC, WUTSEL = LEG
#pragma config IESO = ON, WDTPS = PS32768, FWPSA = PR128, WINDIS = ON
#pragma config FWDTEN = OFF, ICS = PGx1, GWRP = OFF, GCP = OFF, JTAGEN = OFF
#include "xc.h"
/*
* Define the system oscillator frequency that this code will setup
*/
#define FSYS (8000000ul)
#define FCY (FSYS/2ul)
/*
* Initialize this PIC
*/
void PIC_Init(void) {
/* Disable all interrupt sources */
__builtin_disi(0x3FFF); /* disable interrupts for 16383 cycles */
IEC0 = 0;
IEC1 = 0;
IEC2 = 0;
IEC3 = 0;
IEC4 = 0;
__builtin_disi(0x0000); /* enable interrupts */
CLKDIV = 0x0000; /* set for 8MHz FRC clock operations */
AD1PCFG = 0xffff; /* Set for digital I/O */
CMCON = 0x0000;
_NSTDIS = 1; /* disable interrupt nesting */
TRISA = 0xFFFF;
TRISB = 0xFFFF;
}
/*
* Initialize OC1 for PWM operation on PORTB bit RB2/RP2
*/
void OC1_Init(void) {
OC1CON = 0; /* turn off OC1 */
AD1PCFGbits.PCFG4 = 1; /* make GPIO RB2/RP2/AN4 a digital I/O pin */
LATBbits.LATB2 = 0; /* make GPIO RB2/RP2/AN4 output low */
TRISBbits.TRISB2 = 0; /* make GPIO RB2/RP2/AN4 a digital output */
_RP2R = 18; /* magic number to assign OC1 to RB2, see DS39881E-page 109 */
OC1CONbits.OCTSEL = 0; /* Use TIMER2 clock input and prescaler settings as clock for PWM count register */
OC1CONbits.OCM = 0b110; /* Set OC1 for PWM mode, fault shutdown disabled */
T2CON = 0; /* turn off TIMER2 */
T2CONbits.TCKPS = 0b00; /* set TIMER2 prescale as 1:1 */
T2CONbits.TCS = 0; /* set TIMER2 clock source as FSYS/2 */
PR2 = (FCY/4000ul)-1; /* set PWM period to 4KHz */
OC1RS = (PR2+1)>>1; /* set PWM duty cycle to 50% */
T2CONbits.TON = 1; /* turn on TIMER2 */
}
/*
* main application
*/
int main(void) {
PIC_Init();
OC1_Init();
/*
* application process loop
*/
for(;;) {
/* poll for start of PWM period */
if(IFS0bits.T2IF){
IFS0bits.T2IF= 0; /* put a breakpoint here to verify PWM timing with simulator stop watch */
Nop();
Nop();
Nop();
}
}
return 0;
}
This code does run correctly with the MPLABX simulation tool. This is almost never true. IMHO the MPLABX simulator is crap.
This is screen shot of the simulation session working:
An important note on the PIC24FJ64GA002 output compare module is that it is an early silicon implementation and the newer controllers have independent period count registers for each output compare module. This means that the output compare module periods are not tied to the TIMER period on these controllers. I mention this because it really confused me.

Related

How can I write to the flash memory of a PIC24FJ?

I am using a PIC microcontroller, exactly the PIC24FJ128GL305 and I want to save important data in flash memory using MPLAB X IDE V6, one of the data I want to save is -733.5847 and I can't save it, in fact I can't even save integers.
Could anyone help me with a library to do what I want, please?
There is a whole lot you will need to learn before this example will make any sense.
This code does work but it is not even close to what you will actually need to create.
Perhaps you will learn enough from a working example to be able to ask a better question.
/*
* File: main.c
* Author: dan1138
*
* Description:
* Example for Run Time Self Programming (RTSP).
* This is very limited, useful as a test bench but not much more.
*
* Created on December 14, 2022, 9:07 PM
*/
/* Define the system oscillator frequency this code must configure */
#define FSYS (8000000ul)
#define FCY (FSYS/2ul)
// PIC24FJ128GL305 Configuration Bit Settings
// 'C' source line config statements
// FSEC
#pragma config BWRP = OFF // Boot Segment Write-Protect bit (Boot Segment may be written)
#pragma config BSS = DISABLED // Boot Segment Code-Protect Level bits (No Protection (other than BWRP))
#pragma config BSEN = OFF // Boot Segment Control bit (No Boot Segment)
#pragma config GWRP = OFF // General Segment Write-Protect bit (General Segment may be written)
#pragma config GSS = DISABLED // General Segment Code-Protect Level bits (No Protection (other than GWRP))
#pragma config CWRP = OFF // Configuration Segment Write-Protect bit (Configuration Segment may be written)
#pragma config CSS = DISABLED // Configuration Segment Code-Protect Level bits (No Protection (other than CWRP))
#pragma config AIVTDIS = OFF // Alternate Interrupt Vector Table bit (Disabled AIVT)
// FBSLIM
#pragma config BSLIM = 0x1FFF // Boot Segment Flash Page Address Limit bits (Enter Hexadecimal value)
// FOSCSEL
#pragma config FNOSC = FRC // Oscillator Source Selection (Internal Fast RC (FRC))
#pragma config PLLMODE = DISABLED // PLL Mode Selection (No PLL used; PLLEN bit is not available)
#pragma config IESO = ON // Two-speed Oscillator Start-up Enable bit (Start up device with FRC, then switch to user-selected oscillator source)
// FOSC
#pragma config POSCMD = NONE // Primary Oscillator Mode Select bits (Primary Oscillator disabled)
#pragma config OSCIOFCN = ON // OSC2 Pin Function bit (OSC2 is general purpose digital I/O pin)
#pragma config SOSCSEL = ON // SOSC Power Selection Configuration bits (SOSC is used in crystal (SOSCI/SOSCO) mode)
#pragma config PLLSS = PLL_PRI // PLL Secondary Selection Configuration bit (PLL is fed by the Primary oscillator)
#pragma config IOL1WAY = OFF // Peripheral pin select configuration bit (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)
// FWDT
#pragma config WDTPS = PS32768 // Watchdog Timer Postscaler bits (1:32,768)
#pragma config FWPSA = PR128 // Watchdog Timer Prescaler bit (1:128)
#pragma config FWDTEN = OFF // Watchdog Timer Enable bits (WDT and SWDTEN disabled)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config WDTWIN = WIN25 // Watchdog Timer Window Select bits (WDT Window is 25% of WDT period)
#pragma config WDTCMX = WDTCLK // WDT MUX Source Select bits (WDT clock source is determined by the WDTCLK Configuration bits)
#pragma config WDTCLK = LPRC // WDT Clock Source Select bits (WDT uses LPRC)
// FPOR
#pragma config BOREN = OFF // Brown Out Enable bit (Brown Out Disabled)
#pragma config LPCFG = OFF // Low power regulator control (No Retention Sleep)
#pragma config DNVPEN = ENABLE // Downside Voltage Protection Enable bit (Downside protection enabled using ZPBOR when BOR is inactive)
// FICD
#pragma config ICS = PGD1 // ICD Communication Channel Select bits (Communicate on PGEC1 and PGED1)
#pragma config JTAGEN = OFF // JTAG Enable bit (JTAG is disabled)
// FDMTIVTL
#pragma config DMTIVTL = 0xFFFF // Deadman Timer Interval Low Word (Enter Hexadecimal value)
// FDMTIVTH
#pragma config DMTIVTH = 0xFFFF // Deadman Timer Interval High Word (Enter Hexadecimal value)
// FDMTCNTL
#pragma config DMTCNTL = 0xFFFF // Deadman Timer Instruction Count Low Word (Enter Hexadecimal value)
// FDMTCNTH
#pragma config DMTCNTH = 0xFFFF // Deadman Timer Instruction Count High Word (Enter Hexadecimal value)
// FMDT
#pragma config DMTDIS = OFF // Deadman Timer Enable Bit (Dead Man Timer is Disabled and can be enabled by software)
// FDEVOPT1
#pragma config ALTCMPI = DISABLE // Alternate Comparator Input Enable bit (C2INC and C3INC are on their standard pin locations )
#pragma config TMPRPIN = OFF // Tamper Pin Enable bit (TMPRN pin function is disabled)
#pragma config SOSCHP = ON // SOSC High Power Enable bit (valid only when SOSCSEL = 1 (Enable SOSC high power mode (default))
#pragma config ALTI2C1 = ALTI2C1_OFF // Alternate I2C pin Location (I2C1 Pin mapped to SDA1/SCL1 pins)
#pragma config SMB3EN = SMBUS3 // SM Bus Enable (SMBus 3.0 input levels)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include <libpic30.h>
#define MEMORY_USER_CALIBRATION_LOC (_FLASH_PAGE * 24)
typedef struct
{
float fCal;
} stFlashStruct_t;
volatile const __prog__ __attribute__((space(prog), address(MEMORY_USER_CALIBRATION_LOC))) union
{
uint16_t words[_FLASH_PAGE]; /* reserve the entire erase page. Note only the low 16-bits of the instruction word can be accessed with this method. */
struct {
stFlashStruct_t stFlashStruct; /* calibration structure */
};
} CalSpace =
{
.stFlashStruct.fCal = 1.0,
};
int main(void)
{
volatile stFlashStruct_t ReadBack;
/*
* application initialization
*/
ReadBack.fCal = CalSpace.stFlashStruct.fCal;
__builtin_software_breakpoint(); /* breakpoint here to inspect the ReadBack structure with the debugger */
Nop();
Nop();
/* Erase 1024 instruction words starting at address MEMORY_USER_CALIBRATION_LOC */
NVMCON = 0x4003;
NVMADR = __builtin_tbloffset(&CalSpace);
NVMADRU = __builtin_tblpage(&CalSpace);
__builtin_disi(5); // Disable interrupts for NVM unlock
__builtin_write_NVM(); // Start write cycle
while(NVMCONbits.WR == 1);
ReadBack.fCal = CalSpace.stFlashStruct.fCal;
__builtin_software_breakpoint(); /* breakpoint here to inspect the ReadBack structure with the debugger */
Nop();
Nop();
/* Update data in structure to be written */
ReadBack.fCal = -733.5847;
/* Write 2 instruction words starting at address MEMORY_USER_CALIBRATION_LOC */
NVMCON = 0x4001; // Set WREN and word program mode
TBLPAG = 0xFA; // write latch upper address
NVMADR = __builtin_tbloffset(&CalSpace.stFlashStruct);
NVMADRU = __builtin_tblpage(&CalSpace);
__builtin_tblwtl(0,*((uint16_t *)(&ReadBack)+0)); // load low 16-bits of first instruction word
__builtin_tblwth(0,0x00); // make high 8-bits of first instruction word zero
__builtin_tblwtl(2,*((uint16_t *)(&ReadBack)+1)); // load low 16-bits of second instruction word
__builtin_tblwth(2,0x00); // make high 8-bits of second instruction word zero
__builtin_disi(5); // Disable interrupts for NVM unlock sequence
__builtin_write_NVM(); // initiate write
while(NVMCONbits.WR == 1);
ReadBack.fCal = CalSpace.stFlashStruct.fCal;
__builtin_software_breakpoint(); /* breakpoint here to inspect the ReadBack structure with the debugger */
Nop();
Nop();
/*
* Application process loop
*/
for(;;)
{
Nop();
Nop();
Nop();
__delay_ms(100);
}
}

esp32 pico kit - actual clock speed vs crystal vs max_speed etc

I am trying to understand how the clock speed in the esp32 works.
I am running arduino ide 1.8.12 with 1.04 board definition - on a pico kit 4 module .
The device datasheet says it has a 40mhz crystal.
getCpuFrequencyMhz() reports 240mhz
But the following code is generating 1sec interrupts with 80mgz as a base i.e., as if the clock speed is 80mhz.
If I explicitly set the clock speed to 80 mhz then getCpufrequency correctly reports it as having changed, but the code still keeps generating 1sec interrupts. If I set the clock to 40mhz then I finally see interrupts at 2 secs as expected.
I am sure that the explanation is somewhere in expressif's docs, but I have been unable to glean it. Can anyone quickly explain what is going on or point me to some resource that explains this particular circumstance?
---------------
Sample output
getCpuFrequencyMhz() = 240
interrupts so far = 1 - : - mills() = 1018
interrupts so far = 2 - : - mills() = 2018
interrupts so far = 3 - : - mills() = 3018
interrupts so far = 4 - : - mills() = 4018
interrupts so far = 5 - : - mills() = 5018
----------------Sample code
#include "esp32-hal-cpu.h"
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
Serial.printf("getCpuFrequencyMhz() = %d\n",getCpuFrequencyMhz()); //Get CPU clock
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.printf("interrupts so far = %d - : - mills() = %d \n", totalInterruptCounter, millis());
}
}

Pic12f683 only has digital out on pin 2 (GP5)

I've been trying to get started with the PIC12f683 in order to get familiar with the PIC family of microcontrollers.
I've got it hooked up to a Pickit 3, and talking to my PC, that all seems to work fine.
I've been trying various LED flasher examples from the internet but no matter which example code I try, or what I do with the TRISO or GPIO registers, I only get output on pin 2, none of the other GPIO pins will do anything.
Electrically speaking... Pins 1, 4, 6, 7, and 8 are connected to the Pickit for ICSP. Pins 2, 3, 5, and 7 have LEDs with 220 ohm resistors going from the pin to ground, and pins 1 and 8 are connected to a lithium ion battery (~3.7 v).
This is the code I am using currently.
#define _XTAL_FREQ 8000000
#include <xc.h>
// BEGIN CONFIG
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
//END CONFIG
int main()
{
TRISIO =0b00000000; //RB0 as Output PIN
GPIO = 0b00111111;
while(1)
{
GP5=1;
GP4=1;
GP0=1;
GP2=1;
__delay_ms(1000);
GP5=0;
GP4=0;
GP0=0;
GP2=0;
__delay_ms(1000);
}
return 0;
}
I believe the config portion was generated by MPlab, the rest is copied/modified from this instructable:
https://www.instructables.com/id/How-to-Blink-an-Led-With-PIC16F886-/
but the results are the same no matter what example code I use. I'm guessing there's a register or configuration variable I've set wrong somewhere, but I can't figure it out.
You had to switch your Outputs to digital.
int main()
{
TRISIO =0b00000000; //RB0 as Output PIN
ANSEL = 0; // all outputs digital !!!!!
CMCON0 = 0b00000111; //turn Cin Pins as I/O
GPIO = 0b00111111;
while(1)
{
GP5=1;
GP4=1;
GP0=1;
GP2=1;
__delay_ms(1000);
GP5=0;
GP4=0;
GP0=0;
GP2=0;
__delay_ms(1000);
}
return 0;
}
The outputs GP0 ... GP4 are default analog ones.
And please remember GP3 share the pin with MCLR, so it is an input only pin.

rs-485 USB to RS485 C code

#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <sys/ioctl.h> /* ioctl() */
void main(void)
{
int fd;/*File Descriptor*/
printf("\n +----------------------------------+");
printf("\n | USB To RS485 Write |");
printf("\n +----------------------------------+");
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
if(fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyUSB0 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
cfsetispeed(&SerialPortSettings,B4800); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B4800); /* Set Write Speed as 9600 */
SerialPortSettings.c_cflag &= PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS7; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 1; /* Read at least 10 character */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none");
/*---------------------------------------- Controlling RTS and DTR Pins --------------------------------------*/
/* ~RTS(USB2SERIAL) ---> ~RE(MAX485) */
/* ~DTR(USB2SERIAL) ---> DE(MAX485) */
/*------------------------- Putting MAX485 chip in USB2SERIAL in Transmit Mode ---------------------------*/
// //
// ----+ +-----------+ H +-----------+ //
// | | ~RTS| --------------> |~RE | //
// PC |==========>| FT232 | | MAX485 +(A,B)~~~~~~~~~~~~~~~>Data out(RS485) //
// | USB | ~DTR| --------------> | DE | Twisted Pair //
// ----+ +-----------+ H +-----------+ //
// //
//--------------------------------------------------------------------------------------------------------//
//TxMode - DE->High,~RE -> High
int RTS_flag,DTR_flag;
RTS_flag = TIOCM_RTS; /* Modem Constant for RTS pin */
DTR_flag = TIOCM_DTR; /* Modem Constant for DTR pin */
ioctl(fd,TIOCMBIC,&RTS_flag);/* ~RTS = 1,So ~RE pin of MAX485 is HIGH */
ioctl(fd,TIOCMBIC,&DTR_flag);/* ~DTR = 1,So DE pin of MAX485 is HIGH,Transmit Mode enabled */
/*------------------------------- Write data to serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char write_buffer[] = "///?01!"; /* Buffer containing characters to write into port */
char write_buffer1[] = {'\r','\n'};
int bytes_written = 0; /* Value for storing the number of bytes written to the port */
bytes_written = write(fd,write_buffer,7);/* use write() to send data to port */
/* "fd" - file descriptor pointing to the opened serial port */
/* "write_buffer" - address of the buffer containing data */
/* "sizeof(write_buffer)" - No of bytes to write */
printf("\n %s written to ttyUSB0",write_buffer);
bytes_written = write(fd,write_buffer1,2);/* use write() to send data to port */
/* "fd" - file descriptor pointing to the opened serial port */
/* "write_buffer" - address of the buffer containing data */
/* "sizeof(write_buffer)" - No of bytes to write */
printf("\n %s written to ttyUSB0",write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
char buf[20000];
sleep(2);
while(1)
{
printf("tring to read port\n");
int res = read(fd,buf,1);
sleep(1);
printf("%c :: %d\n",buf[0],res);
}
printf("\n +----------------------------------+\n\n\n");
close(fd); /* Close the serial port */
}
--------------------------------------------------------
Setting for running the code :BAUD RATE is 4800 Databits is 7 , Parity is EVEN, and Stopbit is 1.
If i compile the code and run it is not working. Before running the code if i open and close the minicom with BAUD B4800 & 7E1 then my code is working.
Can any one suggest where is the problem why it is not working.

Pic18F2520 Reset

I am trying to control a BMP180 through I2C protocol. The problem is that the Pic resets all the time. I changed the Pic and it is the same.
The config code is the next:
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1H
#pragma config OSC = INTIO7 // Oscillator Selection bits (Internal oscillator block, CLKO function on RA6, port function on RA7)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3 // Brown Out Reset Voltage bits (Minimum setting)
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)
and the main code:
#include <xc.h>
#include <stdint.h>
#define EAUSART_V4
#include <plib/usart.h>
#include "i2c.h"
#define OSCCON_Init 0b11111111
#define BMP180_W 0xEE
#define BMP180_R 0xEF
#define I2C_master_ACK 1
#define I2C_master_NOACK 0
#define I2C_WRITE_CMD 0
#define I2C_READ_CMD 1
#define I2C_START_CMD 0
#define I2C_REP_START_CMD 1
#define I2C_REQ_ACK 0
#define I2C_REQ_NOACK 0
#define SDA_TRIS TRISCbits.RC4
#define SCL_TRIS TRISCbits.RC3
char CaracterRx;
int nummer = 0;
uint8_t data;
uint16_t temperature;
uint8_t BMP180_present(void);
void i2c_master_ack(unsigned char);
uint16_t BMP180_Temperature_Lecture(void);
void main(void) {
char hello[] ={"hello there\r\n\0"};
SSPSTATbits.CKE = 1;
SDA_TRIS = 1;
SCL_TRIS = 1;
OSCCON = OSCCON_Init;
OpenUSART(USART_TX_INT_ON &
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH, 51);
putsUSART("2");
for(int i=0; i<10 ; i++)
__delay_ms(50);
SSPADD=19;
OpenI2C(MASTER,SLEW_OFF);
putsUSART(&hello);
for(int i=0; i<10 ; i++)
__delay_ms(50);
while(1)
{
data = BMP180_present();
temperature = BMP180_Temperature_Lecture();
nummer = data;
putsUSART(nummer);
for(int i=0; i<50; i++)
__delay_ms(50);
}
}
uint8_t BMP180_present(void)
{//returns true if a bmp is detected.
//Detection achieved by looking at the device ID, which is fixed at 0x55.
uint8_t Id;
StartI2C();
WriteI2C(BMP180_W);
WriteI2C(0xD0);
RestartI2C();
WriteI2C(BMP180_R);
Id=ReadI2C();
StopI2C();
return Id;
}
uint16_t BMP180_Temperature_Lecture(void)
{
uint16_t value;
uint8_t prueba1, prueba2;
StartI2C();
WriteI2C(BMP180_W);
WriteI2C(0xF4);
WriteI2C(0x2E);
StopI2C();
__delay_ms(5);
WriteI2C(BMP180_W);
WriteI2C(0xF6);
RestartI2C();
WriteI2C(BMP180_R);
prueba1=ReadI2C();//Value in F6
i2c_master_ack(I2C_master_ACK);
prueba2=ReadI2C();//Value in F7
i2c_master_ack(I2C_master_NOACK);
StopI2C();
value = prueba1<<8 | prueba2;
return value;
}
void i2c_master_ack(unsigned char ack_type)
{
SSPCON2bits.ACKDT = ack_type; // 1 = Not Acknowledge, 0 = Acknowledge
SSPCON2bits.ACKEN = 1; // Enable Acknowledge
while (SSPCON2bits.ACKEN == 1);
}
I send the data via Serial to an Arduino and this prints it on the computer. Almost always when I try to print it, it prints only "2", and sometimes, he writes the sentence and prints the data from the module which contains the BMP180. But most of the time, what Arduino shows me is: 22222222...
I have tested setting the MCLR = OFF, but it is still the same.
The lanes SDA and SCL have a resistance of 4.7k to 3.5V. The module is powered with 3.5V, but the pic with 5V.
I do not think that the problem is too high intensity with this module.
Am I maybe forgetting something?
It is curious that when I touch the pic (when I try to change some wire or something) it automatically resets.
Thank you very much.
Manuel.
Sounds like you have some serious noise issues there. There doesn't seem to be anything wrong with your code at first glance. When an unused pin is left floating, it acts like a high-impedance antenna and basically picks up on any and all signals in the vicinity, whatever they may be. Power consumption also rises dramatically in this case. This may explain why the PIC resets every time you touch it. Based on personal experience, I suggest you do some or all of the following:
Set all your unused pins as digital outputs and pull them down to gnd using the LAT register. For example, if you're not using your RA2 pin, put this at the beginning of your main function:
TRISAbits.RA2 = 0;
LATAbits.LATA2 = 0;
Do this for all your unused pins. It will decrease your power consumption dramatically.
Make sure you've connected the right resistance value between the 5V(in your case) and the reset pin. There are issues sometimes if the value is higher or lower than recommended in the datasheet.
Measure the PIC power supply voltage on the corresponding pins. You could do this with a multimeter, but I recommend that you use an oscilloscope if you have access to one. Hook it up to the power supply pins of the PIC and measure the value while you're sending data over the I2C. There could be a drop in the supply voltage, which causes a brown-out reset, i.e. the voltage drops below 3V in your case and the controller resets. If that's the case, clearing the BOREN bit would be a possible solution, however, such power drops indicate a bigger problem with your circuit, so I suggest you look into it some more.

Resources