Enable data memory PIC 18F4550 - microcontroller

I'm using the PIC18F4550 from microchip with the c compiler: by default the 'program memory' is used, but now I want to use the 'data memory' because it gives me a big more functionality, can enyone just tell me how can I to that in the program language C.
That the code:
#pragma code
/******************************************************************************/
void main (void)
{
TRISD = 0x00; // PORTD als uitgang
TRISB = 0b00110000; // RB4 en RB5 als ingang
TRISA = 0x00; // RA output
RCONbits.IPEN = 0; // prioriteit uit
INTCONbits.GIE = 1; // enable interrupt
INTCONbits.RBIE = 1; // interrupt portB aan
while(1)
{
_asm sleep _endasm
}
}
#pragma interrupt ISR
void ISR (void)
{
int rood[] = {0,0,1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,0,1,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,1,};
if (INTCONbits.RBIF==1)
{
if(PORTBbits.RB5==0) // S3 ingedrukt ?
{
int i = 0;
int b;
do {
LATAbits.LATA2 = rood[i];
LATDbits.LATD1 ^= 1;
b = 0;
do {
b++;
}while(b <= 1500);
i++;
}while(rood[i] <= 50);
//LATDbits.LATD1 ^= 1; // D2 togglen
}
}
INTCONbits.RBIF = 0;
}

The data sheets for this device seem to indicate that the Data Memory is static ram, and that there is no data path from there to the instruciton decode logic, ie, the data memory cannot be used to store program code for execution. If that was your goal, you are out of luck.
In terms of allocating volatile storage, since the program memory does not appear to include any RAM, my guess is that the C compiler will automatically allocate all variables, etc from the data ram.
That leaves only the choice between the "data" EEPROM and the "program" flash for storage of non-volatile (or semi-volatile) data. There you may have to dig into the documentation - it could be this is done with compiler pragmas, or a linker map file, or it could be that access has to be handled indirectly and explicitly through registers.

Related

Can read, but cannot write serial ports on Ubuntu 16.04

I have a strange problem with trying to write data to a serial port.
I am running Ubuntu 16.04 on a NUC7i7DNBE, and am trying to make a serial connection to an Arduino UNO. The Serial API that I am using is found here: http://docs.ros.org/kinetic/api/serial/html/classserial_1_1Serial.html
I have written a simple program which opens the serial port "ttyACM0" to communicate with the arduino. I have tested this code on another computer running Ubuntu 16.04, and everything worked fine, the only permissions I had to set where adding the user to the dialout group.
On the NUC, however, I have added the user to the dialout group. This allowed the program to read from the Arduino, but it still does not write to the Arduino. The Arduino IDE will write to the Arduino just fine, but my program will not.
I am assuming that I am having trouble with serial write permissions in Ubuntu.
Steps I have taken:
I have added the user to the dialout group
I have added a rule in /etc/udev/rules.d/ which states:
SUBSYSTEMS=="tty", GROUP="dialout", MODE="0666"
Afterward, I sent the commands:
sudo chown root:root /etc/udev/rules.d/50-AVCusb.rules
sudo chmod 0644 /etc/udev/rules.d/50-AVCusb.rules
udevadm control --reload-rules
I followed some information found on stack exchange to get to this point:
https://unix.stackexchange.com/questions/111593/allow-non-root-user-to-read-write-dev-files
I have tried using an FTDI device to write to the Arduino port. The FTDI device uses the ttyUSB0 port rather than the ttyACM0 port. The result was the same; can read, but can't write.
I have also run my external hard-drive on the NUC to see if there was any kind of hardware issue. When I ran the program from my external hard drive, I had no problem reading from and writing to the Arduino.
I have not dealt much with Ubuntu permissions or ports in general, please help me find and upload any other information that you may need in order to help me solve this problem.
Code on NUC:
#include <ros/ros.h>
#include <serial/serial.h>
using namespace serial;
Serial ser;
static const uint8_t MOTOR_ID = 0;
void writeMotor(uint8_t byte)
{
size_t size = 4;
uint8_t buffer[size];
buffer[0] = 'G'; //PID
buffer[1] = 'O';
buffer[2] = MOTOR_ID; //address
buffer[3] = byte; //data byte
ser.write(buffer, size);
}
int main() {
ros::init(argc, argv, "servo_esc_driver");
std::string port = "/dev/ttyACM0";
Timeout timeout = Timeout(0, 0, 0, 0, 0);
bytesize_t bytesize = eightbits;
parity_t parity = parity_none;
stopbits_t stopbits = stopbits_one;
flowcontrol_t flowcontrol = flowcontrol_none;
try{
ser.setPort(port);
ser.setBaudrate(115200);
ser.setTimeout(timeout);
ser.setBytesize(bytesize);
ser.setParity(parity);
ser.setStopbits(stopbits);
ser.setFlowcontrol(flowcontrol);
ser.open();
}
catch (SerialException e) {
ROS_FATAL_NAMED("Failed to connect to the Arduino UNO, %s.", e.what());
ros::shutdown();
return 0;
}
uint8_t byte = 90;
writeMotor(byte);
}
Full Code on Arduino
#include <Servo.h>
const byte N = 2;
//Servo esc;
//Servo servo;
Servo servo[N];
//int escPos = 90;
//int servoPos = 90;
int pos[N];
static const byte ESC_PIN = 7;
static const byte SERVO_PIN = 8;
static const byte RPM_FEEDBACK_PIN = 0; //interrpt 0, pin 2
static const byte SERVO_FEEDBACK_PIN = A0;
//const float MUL = 0.7058823529; //180/255
unsigned long lastTime_servoFeedback = 0;
static const byte MOTOR_ID = 0; //ID for differentiating data received and sent over serial connections
static const byte SERVO_ID = 1;
//added for motor data timeout safety feature
static const unsigned long MOTOR_DATA_TIMEOUT = 200; //4 x 50 ms (50 ms time period expected)
static unsigned long lastTimeMotorData = 0;
static const byte NEUTRAL = 90;
unsigned long last_rpm_pulse_update_ms = 0; //used for detecting a stopped car, and rejecting old data when writing to the serial port
unsigned long last_rpm_pulse_time_us = 0;//keeps track of rpms by comparing to system timer
static const long REV_PERIOD_MAX_US = 100000; //in us
unsigned long rev_period = REV_PERIOD_MAX_US; //100 ms is considered too long to be in motion
boolean forward = true;
/*Scratch that, I want these parameters set in ROS:
static const float wheel_radius = 0.05 // meters
static const float revs_to_mps_MUL = //assuming 2.85 gear ratio for brushless motor differential: https://forums.traxxas.com/showthread.php?9080733-Diff-gear-ratios
*/
//boolean rpm_period_updated = false; //rpms must be updated every 100 ms, otherwise the car has stopped, and velocity data should show 0 m/s
void rpm_feedback()
{
//Serial.println("in rpm_feedback");
last_rpm_pulse_update_ms = millis(); //notice the 'ms' here we want to use millisecond for checking whether or not data is valid. millis() can count up to 50 days while micros() only counts up to 70 minutes, thus millis() is used here.
unsigned long time_now = micros(); //use time now for accurate time calculations
unsigned long rev_period_temp = time_now - last_rpm_pulse_time_us; //get spur-gear revolution period
if(rev_period_temp > 0) rev_period = rev_period_temp; //revs are within
else rev_period = REV_PERIOD_MAX_US;
last_rpm_pulse_time_us = time_now; //using 'time_now' ensures that the time taken to get to this point in code does not interfere with rev_period accuracy - - - micros(); //reset time
if(pos[MOTOR_ID] < 90) //determine the direction that the vehicle is traveling in
{
forward = false;
}else forward = true;
//rpm_period_updated = true; not needed, only last_rpm_pulse_time_ms is needed for checking
}
void setup() {
// put your setup code here, to run once:
pinMode(RPM_FEEDBACK_PIN, INPUT_PULLUP);
attachInterrupt(RPM_FEEDBACK_PIN, rpm_feedback,FALLING); //arduino reference recommends using digitalPinToInterrupt(RPM_FEEDBACK_PIN) but the command is not recognized here
analogReference(EXTERNAL); //Using external reference for servo position
for(int i = 0; i < N; i++) //initialize
{
pos[i] = 90;
servo[i].attach(ESC_PIN + i);
}
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() >= 1)
{
if(Serial.read() == 'G')
{
unsigned long t = millis();
while((Serial.available() < 3) && ((millis() - t) < 10)); //wait for the rest of the package, or timeout
if(Serial.available() >= 3)
{
char buf[3];
Serial.readBytes(buf, 3);
if((buf[0] == 'O') && (buf[1] >= 0) && (buf[1] < 2))
{
pos[buf[1]] = byte(buf[2]);
if(buf[1] == MOTOR_ID) lastTimeMotorData = millis(); //time stamp of last motor data retrieval
//Serial.print("buf[2]: ");
//Serial.println(byte(buf[2]), DEC);
//Serial.print("pos: ");
//Serial.println(pos[buf[1]]);
}
}
}
}
if((millis() - lastTimeMotorData) > MOTOR_DATA_TIMEOUT) pos[MOTOR_ID] = NEUTRAL; //stop the motor if data is not being received
for(int i = 0; i < N; i++)
{
servo[i].write(pos[i]);
}
if((millis() - lastTime_servoFeedback) >= 50) // 20Hz 20) //50Hz matches current ROS driver settings
{
lastTime_servoFeedback = millis();
int servo_feedback = analogRead(SERVO_FEEDBACK_PIN);
Serial.write('G'); //PID
Serial.write('O');
Serial.write(SERVO_ID);
//Serial.print(servo_feedback);
Serial.write(lowByte(servo_feedback));
Serial.write(highByte(servo_feedback));
//Serial.println(servo_feedback);
float rev_frequency;
if((last_rpm_pulse_update_ms + 100) < millis()) rev_frequency = 0; //use millis() since it can count up to 50 days, and will not have a chance of a hiccup after 70 minutes of using micros()
//instead, correct period when slowing down, also stop when the maximum threshold is reached
//if((micros() - last_rpm_pulse_time_us) >= REV_PERIOD_MAX_US) rev_frequency = 0; //car is stopped in this case. I decided not to try correcting the period as mentioned above
else rev_frequency = (float) 1/rev_period*1000000;
byte *rev_freq_bytes_to_transmit = (byte *) &rev_frequency;
if(forward == false) rev_frequency = -rev_frequency; //a negative frequency is used for reverse
Serial.write('G'); //PID
Serial.write('O');
Serial.write(MOTOR_ID); //used for addressing
Serial.write(rev_freq_bytes_to_transmit, 4);
}
}
Some good information may be:
snuc#usuavc:~$ udevadm info -a -n /dev/ttyACM0
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/tty/ttyACM0':
KERNEL=="ttyACM0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0':
KERNELS=="1-4:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="cdc_acm"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceClass}=="02"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bInterfaceSubClass}=="02"
ATTRS{bNumEndpoints}=="01"
ATTRS{bmCapabilities}=="6"
ATTRS{supports_autosuspend}=="1"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4':
KERNELS=="1-4"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="02"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bMaxPower}=="100mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 2"
ATTRS{bcdDevice}=="0001"
ATTRS{bmAttributes}=="c0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="4"
ATTRS{devpath}=="4"
ATTRS{idProduct}=="0043"
ATTRS{idVendor}=="2341"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Arduino (www.arduino.cc)"
ATTRS{maxchild}=="0"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="removable"
ATTRS{serial}=="55330313635351207081"
ATTRS{speed}=="12"
ATTRS{urbnum}=="6990"
ATTRS{version}==" 1.10"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
KERNELS=="usb1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{authorized_default}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceProtocol}=="01"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bMaxPower}=="0mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bcdDevice}=="0415"
ATTRS{bmAttributes}=="e0"
ATTRS{busnum}=="1"
ATTRS{configuration}==""
ATTRS{devnum}=="1"
ATTRS{devpath}=="0"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{interface_authorized_default}=="1"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 4.15.0-32-generic xhci-hcd"
ATTRS{maxchild}=="12"
ATTRS{product}=="xHCI Host Controller"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="unknown"
ATTRS{serial}=="0000:00:14.0"
ATTRS{speed}=="480"
ATTRS{urbnum}=="76"
ATTRS{version}==" 2.00"
looking at parent device '/devices/pci0000:00/0000:00:14.0':
KERNELS=="0000:00:14.0"
SUBSYSTEMS=="pci"
DRIVERS=="xhci_hcd"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0330"
ATTRS{consistent_dma_mask_bits}=="64"
ATTRS{d3cold_allowed}=="1"
ATTRS{dbc}=="disabled"
ATTRS{device}=="0x9d2f"
ATTRS{dma_mask_bits}=="64"
ATTRS{driver_override}=="(null)"
ATTRS{enable}=="1"
ATTRS{irq}=="122"
ATTRS{local_cpulist}=="0-7"
ATTRS{local_cpus}=="ff"
ATTRS{msi_bus}=="1"
ATTRS{numa_node}=="-1"
ATTRS{revision}=="0x21"
ATTRS{subsystem_device}=="0x2070"
ATTRS{subsystem_vendor}=="0x8086"
ATTRS{vendor}=="0x8086"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
I decided that the problem was with the ROS version of serial. I decided to try some native linux library, termios, and had success writing to the port!
I found this example code:
https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux
The problem lies in the ros serial installation somehow.
Don't know if you still want to solve this with serial/serial.h, but I think that your problem might be in the timeout settings.
I'm telling you this, 'cause I had the exact same problem, I could read the incoming data, but couldn't write.
The /dev/ttyUSB0 permission was ok, but not the timeout.
I found the following config on internet, gave a try and work. Now I can read and write.
try{
ser.setPort("/dev/ttyUSB0");
ser.setBaudrate(9600);
serial::Timeout to = serial::Timeout::simpleTimeout(10);
ser.setTimeout(to);
ser.open();
return true;
}
catch (SerialException e) {
return 0;

Arduino SD card fails to write when used with another SPI device

I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).

Transmitting a single character over UART from pic16f887 to a PC terminal(Putty, Hyperterminal, etc..)

I am trying to transmit a character "a" from pic16f887 and see the result on the terminal, but all I get is a question mark(using USART terminal), or nothing at all(Putty, Hyperterminal). I am not so great with C, as I'm only a beginer, but I really need to get this working for my school project.. I have tried many codes I've found over the internet, and I did manage to receive a character from the terminal and, lets say, turn on a LED, but I just can't manage to make it send anything. And I have a strong feeling its somewhere in the code.. Im using MPLAB and Hi-Tech C compiler to build the project. Here it is:
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
TRISA = 0;
PORTA = 0;
TRISB = 0;
PORTB = 0;
TRISD = 0;
PORTD = 0;
ANSELH = 0;
init_uart();
while (1)
{
if (cUART_data_flg==1)
{
UART_putc(cUART_char);
cUART_data_flg=0;
}
}
}
void InterruptHandlerLow ()
{
if (RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
// init data receive flag to zero (no data)
TRISC7=1; //Make UART RX pin input
TRISC6=0; //Make UART TX pin output
SYNC = 0; // enables for asynchronous EUART
SPEN = 1; // enables EUSART and sets TX (RC6) as output; ANSEL must be cleared if shared with analog I/O
CREN = 1;
TX9 = 0; // 8bit mode
RX9 = 0;
TXEN = 1; // enables Transmitter
BRGH = 1; // baud rate select
BRG16 = 0;
SPBRG = 25; //baud rate select 9600#4Mhz
SPBRGH = 0;
RCIE=1; // receive interrupt enable
GIE=1; // global interrupt enable
PEIE=1 ; // Peripheral Interrupt Enable bit
}
void UART_putc(unsigned char c)
{
TXEN=0;// disable transmission
TXREG=0x61; // load txreg with data
TXEN=1; // enable transmission
while(TRMT==0) // wait here till transmit complete
{
}
}
Please if someone sees a problem (or more) in this code, help me to crack this ;)
Oh and I am transmitting when pressing a button connected to a TX pin (RC6)..

Interrupt on PIC18 fires only once

I'm trying to get the Timer1 on my PIC18F2550 to fire interrupts every second for countdowns. So far I've been able to establish interrupt priority correctly, as well as other settings, however my ISR only fires once. I've set up my program to print the amount of seconds left in the countdown onto the LCD, so it's obvious to the user how many interrupts have passed. I've made sure to clear the proper interrupt flags in the ISR, since that's what was the source of the problem for the majority of the people having the same issue on google, but this didn't fix it. Everything else about my program has worked fine so far.
(For the sake of testing whether or not the right priority has fired, low counts up instead of down)
Here's the code snippet
//First testing program for PIC18F2550
#include <p18f2550.h>
#include <stdlib.h>
#include <delays.h>
#define _XTAL_FREQ 4915200
#pragma config PLLDIV = 1
#pragma config CPUDIV = OSC1_PLL2
#pragma config FOSC = XT_XT
#pragma config MCLRE = ON
#pragma config BOR = OFF
#pragma config WDT = OFF
#pragma config IESO = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
unsigned char Countdown = 30; (other vars, fcns omitted)
#pragma code high_vector = 0x08
void highvectinterrupt(void){
_asm goto highisr _endasm
}
#pragma code low_vector = 0x18
void lowvectinterrupt(void){
_asm goto lowisr _endasm
}
(...)
void highisr(void){
Countdown--;
PIR1bits.TMR1IF = 0;
}
void lowisr(void){
Countdown++;
PIR1bits.TMR1IF = 0;
}
void main(void){
UCONbits.USBEN=0; //Setup I/O
UCFGbits.UTRDIS=1;
OSCCONbits.SCS1 = 0;
OSCCONbits.SCS0 = 0;
BAUDCONbits.TXCKP=0;
SPBRG = 0x3F; //1200 baud
TRISA = 0x00;
TRISB = 0xFF;
TRISC = 0x00;
beephigh(); //Done, clear the line and beep speaker 1
LATA = 0; //reset
LATC = 0;
Delay10KTCYx(8);
LATAbits.LATA2 = 1; //load the reset
Delay10KTCYx(8);
LATAbits.LATA3 = 1; //stop reset
LATAbits.LATA4 = 1;
LATAbits.LATA2 = 0;
Delay10KTCYx(123);
initlcd();
Delay10KTCYx(10);
setupUI();
LATAbits.LATA0 = 0; //Done, clear the line and beep speaker 2
beeplow();
INTCON = 0; //Reset high interrupt flags and disable interrupts
T1CON = 0x11110100; //16 bit r/w; internal system clock; 8x prescale; timer1 osc disabled
TMR1H = 0; //Clear the counting register
TMR1L = 0;
PIE1bits.TMR1IE = 1; //Enable Interrupts on Timer1
PIR1bits.TMR1IF = 0; //Clear the flag if set
RCONbits.IPEN = 1; //Enable priority levels
INTCON2bits.TMR0IP = 0; //Timer0 on low priority
IPR1bits.TMR1IP = 0; //Timer1 on low priority
IPR1bits.RCIP = 1; //RS232 on high priority
INTCONbits.GIEL = 1; //Enable all low priority interrupts
INTCONbits.GIEH = 1; //Enable all high priority (must be enabled for low priority)
T1CONbits.TMR1ON = 1; //Turn Timer1 on
while(1){ //Idle and refresh screen
Delay10KTCYx(8);
bin2ascii(Countdown);
cmdlcd(0xCE);
putclcd(ConvRegTens);
putclcd(ConvRegOnes);
}
}
Ultimately I'm staring at an LCD with "31" on it. It's likely a single flag that I'm not setting properly that's causing nothing to work right, but as far as I've checked everything's being enabled and being cleared properly. What am I doing wrong? I'd appreciate any help, this is enormously frustrating.
Also: I've cleared all breakpoints so it's not halting anywhere, and program the latest version on compile. So I've ruled out running an old busted version of the code.
Edit: To clarify, this code is only for functionality; it will not fire every second but rather much faster. Once I get it working I'll play the overflow counting to get it to 1 second.
You are not finishing ISR routine correctly!
#pragma code low_vector = 0x18
void lowvectinterrupt(void){
_asm goto lowisr _endasm
}
After ISR execution the interrupt must be switched on again, so the lowvectinterrupt must be finished with RETFIE instruction and at least flags and WREG register must be restored.
Normaly is in ISR routine declared like:
static void interrupt isr(void)
{
}

ATTiny array update error

I am making a persistence of vision display using an ATTiny85, programmed with Arduino using the arduino-tiny core.
It consists of a stick with 16 LEDs on it which is spun round quickly to 'draw' a picture in the air. The display buffer is represented by an array, the next index of which is output every time the timer fires. It uses a hall sensor wired to INT0 to sense top dead centre, where it zeroes the array index.
It is an 8 bit processor and I have 16 LEDs connected to LED drivers, so I actually use two arrays for the display.
So the weird thing is that when I initialised the display with a cross pattern, it displayed a bunch of broken lines; so I zeroed it first in case memory had some random stuff in it. Now it doesn't display anything (even though I write the cross pattern to it straight after zeroing it). I have no idea what is happening, any ideas?
I had it previously outputting just the index value, and the picture it traces appears to look like counting binary, so I think the hardware is working.
Note that I'm not using digitalWrite because it disables interrupts which might throw the timing off.
Here is the code: (sorry it's quite a lot)
#define COLUMNCOUNT 180
const int datapin = 4;
const int clockpin = 0;
const int latchpin = 1;
const int rxpin = 3;
const int hallpin = 2;
volatile int columns0[COLUMNCOUNT];
volatile int columns1[COLUMNCOUNT];
volatile int counter = 0;
void setup()
{
pinMode(datapin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(latchpin, OUTPUT);
pinMode(rxpin, INPUT);
pinMode(hallpin, INPUT);
//make sure the arrays are all zeroed
for (int i = 0; i < COLUMNCOUNT; i++)
{
columns0[i] = 0;
columns1[i] = 0;
}
//make a cross pattern
columns0[0] = 255;
columns1[0] = 255;
columns0[45] = 255;
columns1[45] = 255;
columns0[90] = 255;
columns1[90] = 255;
columns0[135] = 255;
columns1[135] = 255;
//turn on the timer (prescale CK/16)
OCR1A = 255;
OCR1C = 255;
TCNT1 = 0;
TIMSK = _BV(OCIE1A);
TCCR1 = _BV(CTC1) | _BV(CS12) | _BV(CS10);
GIMSK = _BV(INT0);
sei();
}
void loop()
{
//nothing to do here
}
ISR(TIMER1_COMPA_vect)
{
if (counter < COLUMNCOUNT)
counter++;
outputWord(columns0[counter], columns1[counter]);
}
ISR(INT0_vect)
{
counter = 0;
}
void outputByte(int b)
{
int currentBit;
for (int i = 0; i < 8; i++)
{
currentBit = (b & 128) == 128;
PORTB = _BV(clockpin) | (currentBit ? _BV(datapin) : 0);
PORTB = PORTB ^ _BV(clockpin);
b <<= 1;
}
}
void outputWord(int hi, int lo)
{
outputByte(hi);
outputByte(lo);
PORTB = _BV(latchpin);
PORTB = 0;
}
Per C standard, global variables are initialised to 0. As such,
//make sure the arrays are all zeroed
for (int i = 0; i < COLUMNCOUNT; i++)
{
columns0[i] = 0;
columns1[i] = 0;
}
is not necessary. That action is taken care of automatically when the __do_clear_bss section is executed.
Also, as per C standard, the int type must be at least 16 bits wide. In AVR, the minimum is used. If you are using the free software toolchain, it contains inttypes.h which provides the functionality offered by stdint.h and some extra stuff. This was mentioned in another answer.
The statement:
PORTB = PORTB ^ _BV(clockpin);
can be rewritten as:
PINB = _BV(clockpin);
which compiles to only 1 instruction, as per Atmel's datasheets.
Macros provided by pgmspace.h can read from flash. Notice that you can not change the contents of flash as your program runs in most AVR chips.
Beware local/global variables and stack/heap collisions when handling this much data.
I've figured it out: it's an SRAM issue. The ATTiny85 only has 512 bytes of SRAM, so it can't hold all that data in memory at the same time. I'm investigating storing the data in flash memory using the PROGMEM directive instead.
I am also doing a Persistance of Vision (POV) with the Attiny44. (I am programming it via the Arduino as an ISP)
user Ben Jackson's tip for conserving SRAM memory was spot on: I originally was using "int"'s for my arrays and my Attiny would bug out if I tried to include additional arrays- However when I simply declared all of my arrays as "unsigned char"'s my code worked fabulously as it should!
Next time I will either order attiny45's or similar for more SRAM memory, and continue to use unsigned char's for my array declarations.
Thanks for the discussion guys!

Resources