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());
}
}
Related
I'm working on my first ESP32 project using a DFRobot Firebeetle 2 (ESP32-WROOM-32E) and the Arduino IDE (configured as per DFRobot's instructions). I'm trying creating a Telegram bot which will send a message when the temperature exceeds a certain value. This part is working in the loop() method, but now I'm trying to add a 'status button' which triggers an interrupt to send a status message. I plan to use the ESP32's sleep function, hence using an interrupt rather than checking the button in loop() - I am aware that loop() doesn't execute when using sleep. The problem is sending a message in the interrupt method is causing an error, but I don't know how to resolve it.
If I reduce minStatusMsgInterval to 250 and call SendStatusMessage(); at the end of setup() I receive the message, so the function works, just not when it's called from an interrupt. The error mentions wdt timeout so I'm thinking bot.sendMessage() is taking too long? But if that is the case, I can't make it any quicker, so is there another way to achieve this? or have I misinterpreted the error completely?
#include <WiFi.h>
#include "WiFiClientSecure.h"
#include <ESP32Time.h>
#include <DFRobot_DHT11.h>
#include <UniversalTelegramBot.h>
//WiFi
#define WLAN_SSID "ESP32Test"
#define WLAN_PASS "*********"
//WiFiFlientSecure for SSL/TLS support
WiFiClientSecure client;
//Time
ESP32Time rtc(0); // offset in seconds; 0 = GMT, 3600 = GMT+1
//Telegram
#define TELEGRAM_TOKEN "*********:*************************"
#define CHAT_ID "**********"
UniversalTelegramBot bot(TELEGRAM_TOKEN, client);
//Temperature
DFRobot_DHT11 DHT;
#define DHT11_PIN D11
//Buttons
#define ONBOARD_BUTTON_PIN 27 //ESP32 pin 27
#define STATUS_BUTTON_PIN D10 //ESP32 pin 12
int StatusButtonLastInterrupt = 0;
//Alerts
int alertValue = 27;
bool alertSent = false;
int minStatusMsgInterval = 5000;
void IRAM_ATTR SendStatusMessage() {
if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval) return; //Prevent executing multiple times per button press or more frequent than required
String message = "Temperature Monitor Status\n\n";
message += "Internal temperature: " + String(DHT.temperature) + "C\n";
message += "Internal humidity: " + String(DHT.humidity) + "%\n";
//message += "System time: " + rtc.getDateTime(); // Causes ESP to crash and reset. Error: abort() was called at PC 0x40084cf7 on core 1
//TODO: Check WiFi is connected first - will need to connect when woken from sleep
bot.sendMessage(CHAT_ID, message, ""); // Causes ESP to crash and reset. Error: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
StatusButtonLastInterrupt = millis();
}
void SyncNTP() {
Serial.print("Retrieving time: ");
configTime(0, 3600, "time.google.com"); // get UTC time via NTP
time_t now = time(nullptr);
while (now < 24 * 3600)
{
Serial.print(".");
delay(100);
now = time(nullptr);
}
rtc.setTime(now); //Set the time on the realtime clock
Serial.println(rtc.getDateTime());
}
void setup() {
pinMode(ONBOARD_BUTTON_PIN, INPUT_PULLUP);
pinMode(STATUS_BUTTON_PIN, INPUT);
Serial.begin(115200);
//Interrupts
attachInterrupt(STATUS_BUTTON_PIN, SendStatusMessage, FALLING);
// Connect to WiFi access point.
Serial.println(); Serial.println();
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
//Serial.print(".");
Serial.print("WiFi Status: ");
Serial.println(WiFi.status());
}
Serial.println();
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
SyncNTP();
}
void loop() {
DHT.read(DHT11_PIN);
Serial.print("temp:");
Serial.print(DHT.temperature);
Serial.print(" humi:");
Serial.println(DHT.humidity);
if (DHT.temperature >= alertValue)
{
if (!alertSent)
{
bot.sendMessage(CHAT_ID, "TEMPERATURE ALERT: Internal temperature is: " + String(DHT.temperature), "");
alertSent = true;
}
} else {
if (alertSent)
{
bot.sendMessage(CHAT_ID, "Alert Cleared: Internal temperature is: " + String(DHT.temperature), "");
alertSent = false; //Reset the flag when temperature drops below alertValue
}
}
delay(1000);
}
Serial Monitor Output:
Connecting to ESP32Test
WiFi Status: 6
WiFi Status: 6
WiFi Status: 6
WiFi Status: 6
WiFi Status: 3
WiFi connected
IP address: 192.168.1.2
Retrieving time: ....................Sun, Feb 19 2023 22:23:38
temp:25 humi:57
temp:24 humi:53
temp:24 humi:60
temp:24 humi:60
temp:24 humi:60
temp:24 humi:60
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
Core 1 register dump:
PC : 0x40090362 PS : 0x00060f34 A0 : 0x8008f47e A1 : 0x3ffbeb00
A2 : 0x3ffde700 A3 : 0x3ffbd994 A4 : 0x00000004 A5 : 0xb33fffff
A6 : 0x00000001 A7 : 0x00000001 A8 : 0x3ffbd994 A9 : 0x3ffbd994
A10 : 0x00000019 A11 : 0x00000019 A12 : 0x3ffc3afc A13 : 0xb33fffff
A14 : 0x00000001 A15 : 0x00000001 SAR : 0x0000000f EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff
Core 1 was running in ISR context:
EPC1 : 0x400e8e33 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40090362
Backtrace:0x4009035f:0x3ffbeb000x4008f47b:0x3ffbeb20 0x4008de7c:0x3ffbeb40 0x40106ab7:0x3ffbeb80 0x400f408f:0x3ffbeba0 0x401071c5:0x3ffbebd0 0x40107464:0x3ffbebf0 0x400f379d:0x3ffbec40 0x400d49d2:0x3ffbec60 0x400d472d:0x3ffbeed0 0x400d483e:0x3ffbef00 0x400d6c31:0x3ffbef20 0x400d7ece:0x3ffbef80 0x400d8406:0x3ffbf000 0x4008139e:0x3ffbf070 0x400d93f5:0x3ffbf0d0 0x40084a8d:0x3ffbf0f0 0x40173c7f:0x3ffc78f0 0x400e82e9:0x3ffc7910 0x4008e417:0x3ffc7930
Core 0 register dump:
PC : 0x40090522 PS : 0x00060634 A0 : 0x8008fc1b A1 : 0x3ffb3290
A2 : 0x3ffbf108 A3 : 0x3ffb32ac A4 : 0x00060623 A5 : 0xb33fffff
A6 : 0x0000cdcd A7 : 0x0000abab A8 : 0x0000abab A9 : 0x0000abab
A10 : 0x3ffde770 A11 : 0x000000d0 A12 : 0x3ffc6948 A13 : 0xb33fffff
A14 : 0x00000001 A15 : 0x00000001 SAR : 0x00000011 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff
Backtrace:0x4009051f:0x3ffb32900x4008fc18:0x3ffb32d0 0x4008dd9c:0x3ffb32f0 0x401069c0:0x3ffb3330 0x40106d0e:0x3ffb3350 0x400f56bb:0x3ffb3370 0x400f5739:0x3ffb3390 0x400f812c:0x3ffb33b0 0x400f8211:0x3ffb33e0 0x40108557:0x3ffb3400 0x400f3f19:0x3ffb3420
ELF file SHA256: 0000000000000000
Rebooting...
ets Jul 29 2019 12:21:46
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1412
load:0x40078000,len:13400
load:0x40080400,len:3672
entry 0x400805f8
Connecting to ESP32Test
In general, interrupt handlers need to do as little as possible and return as quickly as possible. Doing too much or calling unsafe functions (which almost all functions will be) leads to programs crashing exactly the way you saw.
Interrupts, as the name indicates, interrupt whatever code is running and execute the interrupt's handler. The handler has no idea what state the code that was interrupted is in. It could easily be in an inconsistent state while it's performing a computation; calling it while it's in an inconsistent state is likely to corrupt memory or cause it to crash or behave erratically. Unless software is specifically designed to be called from an interrupt handler you must assume it's not safe to do so.
As you noticed, the ESP32 requires an interrupt handler to be marked with the IRAM_ATTR attribute - this tells the ESP32 to always keep this code in "Instruction RAM" so that it's always available to execute. The ESP32 isn't able to pull code in from flash storage on demand to service an interrupt. That means that not only does the interrupt handler have to be in IRAM, all functions it calls must be as well. IRAM is a scarce resource, so you want to use as little of it as possible - calling Telegram from an interrupt handler means that not only does all of the Telegram code need to be in IRAM but the entire TCP/IP network stack needs to be. Which also means you'd have to modify every single function in the TelegramBot and network stack to be declared IRAM_ATTR.
Obviously that's not going to work.
Unless you really know what you're doing, the safest way to code an interrupt handler is to set a flag variable indicating there's work to be done, store any data that needs to be saved for the work in other variables and return.
In your case it would look something like this:
volatile boolean should_send_telegram_message = false;
void IRAM_ATTR SendStatusMessage() {
if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval)
return; //Prevent executing multiple times per button press or more frequent than required
should_send_telegram_message = true;
}
void loop() {
if(should_send_telegram_message) {
should_send_telegram_message = false;
String message = "Temperature Monitor Status\n\n";
message += "Internal temperature: " + String(DHT.temperature) + "C\n";
message += "Internal humidity: " + String(DHT.humidity) + "%\n";
//message += "System time: " + rtc.getDateTime(); // Causes ESP to crash and reset. Error: abort() was called at PC 0x40084cf7 on core 1
//TODO: Check WiFi is connected first - will need to connect when woken from sleep
bot.sendMessage(CHAT_ID, message, ""); // Causes ESP to crash and reset. Error: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
StatusButtonLastInterrupt = millis();
}
// do other loop() stuff
}
The volatile attribute on should_send_telegram_message tells the compiler that this variable may unexpectedly have its value changed (as the interrupt handler may do) so that the compiler will avoid doing certain optimizations that depend on the variable not unexpectedly changing.
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.
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.
When I'm trying to build what seems to be any code in the Arduino IDE, it fails with this error:
Arduino: 1.6.5 (Mac OS X), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"
/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/USBCore.cpp:19:19: fatal error: Reset.h: No such file or directory
#include "Reset.h"
^
compilation terminated.
Error compiling.
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
The code I'm trying to build is from https://www.arduino.cc/en/Tutorial/Fade:
/*
Fade
This example shows how to fade an LED on pin 9
using the analogWrite() function.
The analogWrite() function uses PWM, so if
you want to change the pin you're using, be
sure to use another PWM capable pin. On most
Arduino, the PWM pins are identified with
a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.
This example code is in the public domain.
*/
int led = 9; // the PWM pin the LED is attached to
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup() {
// declare pin 9 to be an output:
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// set the brightness of pin 9:
analogWrite(led, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
Why is this happening? I don't think I've changed any of the Arduino libraries, but wondering if that's the case now. A find in /Applications/Arduino.app/ lists no files called Reset.h, however, I did find a ~/Library/Arduino15/packages/arduino/hardware/sam/1.6.4/cores/arduino/Reset.h.
Building with Arduino IDE 1.6.5, using a Mega 2560 and /dev/cu.usbmodem1421.
It turns out my Android installation was modified, and the modified USBCore.cpp wasn't really correct for this version (1.6.5) of Arduino. Reinstalling fixed the problem.
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.