printf for p89v664 prints junk characters from actual micro controller - 8051

I am trying to print message on serial terminal from p89v664 using following code,
#include<P89V66x.H>
#include<stdio.h>
char putchar(char c) {
if (c == '\n') {
while (!TI);
TI = 0;
S0BUF = 0x0d;
}
TI = 0;
S0BUF = c;
while (!TI);
return c;
}
int printf(char*str) {
unsigned int cnt = 0;
while(*str != '\0')
{
putchar(*str);
cnt++;
str++;
}
}
void delay(unsigned int i) {
int d = 100;
for(;i!=0;i--) {
for(;d!=0;d--);
d = 100;
}
}
int main(void) {
/**Serial init*/
S0CON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xF6; /* TH1: reload value for 9600 baud */
TR1 = 1; /* TR1: timer 1 run */
TI = 1;
while(1) {
printf("Hello\n");
delay(300);
printf("Hello World\n");
delay(10000);
}
}
above program works fine till the time printf function definition in this program is not commented.
If printf function in above program is commented to use printf from standard library then junk characters are printed on serial console. (i used putty).
I used Keil uVision V4.14.4.0 compiler.
Is there anything missing?
I dont understand what is wrong with this program.

After some experiments i found that problem was with keil uVision4 evaluation version.
I compiled this code using sdcc and ran it and it worked. May be keil evaluation version's limitation was creating problem. Thank very much you Mellowcandle for all replies.
Edit:
#include <P89V66x.H>
#include<stdio.h>
void putchar(char c) {
TI = 0;
S0BUF = c;
if (c == '\n') {
while (!TI);
TI = 0;
S0BUF = 0x0d;
}
while (!TI);
}
int main(void) {
/**Serial init*/
unsigned short int c = 65334;
S0CON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
/**For 11.0592 crystal
value should TH = -3 or
TH1 = FD*/
TH1 = 0xF6; /* TH1: reload value for 9600 baud for
18 Mhz cyrstal */
TR1 = 1; /* TR1: timer 1 run */
while(1) {
printf("Hello %u\n", c);
delay(300);
printf("Hello World %u\n" ,c);
delay(10000);
}
}
command used to compile this code is,
sdcc {filename}

Related

Issue while reading data from I2c Slave device with PIC16F886

I am newbie to Pic Programming, I am using MPLAb & Hitech compiler to execute above code. I am trying to Interface PIC16F886 with ISL12022M Real time I2C device. i copied code example written for DS1307 interface with 16F887A PIC. I have capable to inteface Basic functionality with above . In below code While write into ISL12022M o could able to see data what i have send in memory register But as when Trying to read rtc time i could able to read last memory write value From SSPBUF. let me know any error in below code.
once I2c read value should be displayed on 4 digit seven segment display.
I think I am doing Misatake in this part. while Reading data i m just sending address so whatever last written in address it displaying.
#include <htc.h>
#include <stdio.h>
#include<pic.h>
#include<stdint.h>
#define _XTAL_FREQ 40000000
unsigned int i=0;
unsigned int k=0;
unsigned int count;
#define Pulse RA5
#define LED RC0
#define LED1 RC2
#define CONTROLREG 0xFF
#define SDA RC4 // Data pin for i2c
#define SCK RC3 // Clock pin for i2c
#define SDA_DIR TRISC4 // Data pin direction
#define SCK_DIR TRISC3 // Clock pin direction
#define DP RA4
#define I2C_SPEED 100 // kbps
unsigned short int cnt, num,Dgt=0;;
unsigned short int temp1,temp2,temp3;
unsigned short sec;
unsigned short min;
unsigned short hour;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short day;
unsigned short int temp=0;
unsigned short r_data;
#define Seg1 0x01
#define Seg2 0x02
#define Seg3 0x04
#define Seg4 0x08
void SetSeg(unsigned short data, unsigned short segno)
{
switch(data)
{
case 0: PORTB = 0x3F; break;
case 1: PORTB = 0x06; break;
case 2: PORTB = 0x5B; break;
case 3: PORTB = 0x4F; break;
case 4: PORTB = 0x66; break;
case 5: PORTB = 0x6D; break;
case 6: PORTB = 0x7D; break;
case 7: PORTB = 0x07; break;
case 8: PORTB = 0x7F; break;
case 9: PORTB = 0x6F; break;
default : PORTB = 0X00; break;
}
if(segno==1)
{
PORTA = Seg4;
}
if(segno==2)
{
PORTA = Seg3;
}
if(segno==3)
{
PORTA = Seg2;
}
if(segno==4)
{
PORTA = Seg1;
}
}
void Delay(int k)
{
int j;
for(j=0;j<k;j++);
}
void InitI2C(void)
{
SDA_DIR = 1; // Make SDA and
SCK_DIR =0; // SCK pins input
SSPCON = 0b00111000; //enables port for i2c
SSPCON2 = 0b00000000;
SSPADD = 10; // 100KHz = 8MHz/4(SSPADD+1)
// SSPSTAT = 0b11000000; // Slew rate disabled
}
void i2c_waitForIdle(void)
{
unsigned int i2ctimeout;
while(1)
{
i2ctimeout++;
if(i2ctimeout > 10)
{
i2ctimeout = 0;
return;
}
}
}
void I2C_Start(void)
{
SEN = 1; // Send start bit
i2c_waitForIdle();
/* while(!SSPIF); // Wait for it to complete
SSPIF = 0; // Clear the flag bit*/
}
void I2C_ReStart(void)
{
RSEN = 1; // Send Restart bit
i2c_waitForIdle();
/* while(!SSPIF); // Wait for it to complete
SSPIF = 0; // Clear the flag bit
while(RSEN==1);*/
}
void I2C_Stop(void)
{
PEN = 1; // Send stop bit
i2c_waitForIdle();
}
void I2C_Send_ACK(void)
{
ACKDT = 0; // 0 means ACK
ACKEN = 1; // Send ACKDT value
i2c_waitForIdle();
}
void I2C_Send_NACK(void)
{
ACKDT = 1; // 1 means NACK
ACKEN = 1; // Send ACKDT value
i2c_waitForIdle();
}
unsigned char I2C_Write( unsigned char i2cWriteData )
{
i2c_waitForIdle();
SSPBUF = i2cWriteData;
return (!ACKSTAT); // function returns '1'
}
int I2C_Read( unsigned char ack )
{
unsigned char i2cReadData;
//unsigned int i2cReadData;
i2c_waitForIdle();
RCEN = 1;
SDA=1;
SCK=1;
i2c_waitForIdle();
i2cReadData = SSPBUF;
SCK=0;
i2c_waitForIdle();
SCK=1;
if(ack)
{
ACKDT = 0;
}
else
{
ACKDT = 1;
}
ACKEN = 1; // send acknowledge sequence
return( i2cReadData );
}
unsigned int bcdtodecimal(unsigned int bcd)
{
unsigned int decimal;
decimal = (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
return decimal;
}
void Init_ISL12022M(void)
{
I2C_Start(); // Start I2C communication
I2C_Write(0XD0); //Write Device Address
I2C_Write(0X08); //
I2C_Write(0X41); // Write 0x00 to Control register to disable SQW-Out
I2C_Stop(); // Stop I2C communication after initilizing
}
unsigned int Write_ISL12022M(unsigned short address, unsigned short w_data)
{
I2C_Start(); // Start I2C communication
I2C_Write(0XD0);
I2C_Write(address); //write address to write data
I2C_Write(w_data); //write data into hexadecimal
I2C_Stop();//stop I2C communication
return(w_data);
}
unsigned short Read_ISL12022M(unsigned short address)
{
I2C_Start();
I2C_Write(address); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
I2C_Write(address);
I2C_ReStart();
I2C_Write(0xD1); //0x68 followed by 1 --> 0xD1
r_data=I2C_Read(0);
I2C_Stop();
return(r_data);
}
void SetDateTime()
{
I2C_Start();
I2C_Write(0xD0);
I2C_Write(0x00);
sec= Write_ISL12022M(0X00, 12); //01 sec
min = Write_ISL12022M(0X01,52); //01 sec
hour = Write_ISL12022M(0X02,9); //01 sec
day= Write_ISL12022M(0X03,7); //01 sec
date = Write_ISL12022M(0X04, 29); //01 sec
month =Write_ISL12022M(0X05,07); //01 sec
year = Write_ISL12022M(0X06,17); //01 sec
I2C_Stop();
}
void RTC_GetDateTime()
{
I2C_Start(); // Start I2C communication
I2C_Send_ACK();
sec = I2C_Read(1); // read second and return Positive ACK
I2C_Send_ACK();
min = I2C_Read(1); // read minute and return Positive ACK
I2C_Send_ACK();
hour= I2C_Read(0); // read hour and return Negative/No ACK
I2C_Send_ACK();
day = I2C_Read(1); // read weekDay and return Positive ACK
I2C_Send_ACK();
date= I2C_Read(1); // read Date and return Positive ACK
I2C_Send_ACK();
month=I2C_Read(1); // read Month and return Positive ACK
I2C_Send_ACK();
year =I2C_Read(0); // read Year and return Negative/No ACK
I2C_Send_ACK();
I2C_Stop(); // Stop I2C communication after reading the Date
}
void interrupt isr(void)
{
if(TMR1IF==1)
{
TMR1H=0xF6; // Load the time value(0xBDC) for 100ms delay
TMR1L=0x18; //Timer1 Interrupt for 65000
TMR1IF=0; // Clear timer interrupt flag
Dgt++;
if(Dgt>=5)
{
Dgt=0;
LED=!LED;
}
}
}
void Timer1_Interrupt()
{
INTCON = 0b00000000;
PIE1=0b00000001;
PIR1=0x01;
TMR1H=0x0B;
TMR1L=0xDC;
T1CON=0x31;
}
void Init_Controller()
{
cnt=100;
TRISC=0b01000000; // Intialize INput & output pheripherals
TRISB=0b10000000;
PORTB = 0b00000000;
TRISA=0b0000000;
ADCON0 = 0b00000000;
ANSEL = 0b00000000;
Timer1_Interrupt();
}
void main(void)
{
Init_Controller();
/* GIE=1;
PEIE=1;
TMR1IE=1; */
InitI2C();
Init_ISL12022M();
SetDateTime();
while(1)
{
RTC_GetDateTime();
SetSeg(year/ 10,2);
SetSeg(year%10,1);
}
}
The lines like:
I2C_Write(0XD0); //Write Device Address
are not a valid device addresses. Use 0xDE (or 0xAE for User SRAM)
From the datasheet:
Following a start condition, the master must output a Slave Address Byte. The 7 MSBs are the device identifiers. These bits are “1101111” for the RTC registers and “1010111” for the User SRAM.

bootloader avr atmega128RFA1

I am also working on the bootloader.
I had the problem in the following:
Once the cmd 'B' is received, later, 'F' is received, then I would start to call block load.
static void start_block_flash_load(uint16_t size, uint32_t *addr) {
uint16_t data_word;
uint8_t sreg = SREG;
uint16_t temp;
int i;
uint8_t my_size;
fprintf(lcdout, "B");
cli();
// Disable interrupts
(*addr) <<= 1;
if (size <= SPM_PAGESIZE) {
boot_page_erase(*addr);
boot_spm_busy_wait();
fprintf(lcdout, "%"PRIu16, size);
uint16_t i;
//store all values. PROBLEM here!!!
my_size = 208;
uint8_t buf[SPM_PAGESIZE] = { 0 };
for (i = 0; i < my_size; i++) {
//for (i=0; i<size; i++){
buf[i] = uart_getc();
// lcd_clear();
// lcd_setCursor(0, 2);
// fprintf(lcdout, "%3d", i);
// _delay_ms(500);
}
for (i = 0; i < my_size; i += 2) { //if size is odd, then use do-while
uint16_t w = buf[i];
w += buf[i + 1] << 8; //first one is low byte, second is high???
boot_page_fill((*addr)+i, w);
}
boot_page_write(*addr);
boot_spm_busy_wait();
(*addr) >>= 1;
uart_putc('\r');
} else
uart_putc('?');
boot_rww_enable ();
SREG = sreg;
}
I can see on the lcd that the size of the block is 256. However, when entering the loop to collect data, it will get stuck.
I tested with my_size and I found that only if my_size=208 the program will run further.
The strange thing is that if I put some statements inside the loop, e.g.
lcd_clear();
lcd_setCursor(0, 2);
then 'i' which I printed out on lcd will not go up to 140 something. I put different statements, the 'i' will give different value. That is very strange, since the uart_getc() will not lose data.
What I expect is that the loop will go up to 256. I cannot figure out what happened there.
Please help if you have any idea.
Thanks

Is it possible to do interactive user input and output simulation in VHDL or Verilog?

For example, I would like to run a simulation for an interactive game like: https://github.com/fabioperez/space-invaders-vhdl without an FPGA, such that:
signals are set by keyboard keys
outputs can be displayed on a window
http://www.nand2tetris.org/ does this, but is uses a simplified custom educational language for it.
VHDL's textio's read(input and write(output get somewhat close, but not quite:
read(input waits for a newline, we'd want something that can detect is a keyboard key is pressed or not
write(output: would need some way to flush data to ensure that the renderer that will emulate, say, a display gets it
we need some way to throttle simulation speed
Of course, I don't need to do everything in VHDL: I just need a minimal way to communicate with VHDL synchronously with other programs, and then I can do the e.g. display with SDL in C.
Also asked at: https://github.com/tgingold/ghdl/issues/92
Verilator
Verilator is a perfect solution for this application.
It exposes the Verilog simulation loop to C++ (and transpiles the Verilog to C++), allowing you to set inputs, and get outputs from C++.
See the CONNECTING TO C++ example from the docs: http://www.veripool.org/projects/verilator/wiki/Manual-verilator
So you can just plug that into SDL / ncurses / etc. without any IPC.
For a simulator independent solution, it might be worth looking into the foreign language APIs of VHDL (VHPI) / Verilog (DPI) as mentioned in this comment, but there are few examples of how to use those, and you'll have to worry about IPC.
Minimal runnable example:
A related project that implements nand2tetris in Verilator + SDL can be found at: https://hackaday.io/project/160865-nand2tetris-in-verilog-part3-verilator-and-sdl2
Install dependencies on Ubuntu 22.04:
sudo apt install libsdl2-dev verilator
Makefile
.POSIX:
.PHONY: all clean run
RUN ?= move
OUT_EXT ?= .out
VERILATOR_DIR = ./obj_dir/
all: $(VERILATOR_DIR)Vmove display$(OUT_EXT)
$(VERILATOR_DIR)Vmove: move.v move.cpp fps.hpp
verilator -Wall --cc move.v --exe move.cpp
make -C obj_dir -f Vmove.mk Vmove CXXFLAGS='--std=c++11 -Wall' LIBS='-lSDL2'
display$(OUT_EXT): display.cpp
g++ -o '$#' '$<' -lm -lSDL2
clean:
rm -rf obj_dir *'$(OUT_EXT)'
run: all
'$(VERILATOR_DIR)V$(RUN)'
move.v
module move(
input wire clock,
input wire reset,
input wire up,
input wire down,
input wire left,
input wire right,
output reg [1:0] x,
output reg [1:0] y
);
always # (posedge clock) begin
if (reset == 1'b1) begin
x <= 0;
y <= 0;
end
else begin
if (up == 1'b1) begin
y <= y - 1;
end
if (down == 1'b1) begin
y <= y + 1;
end
if (left == 1'b1) begin
x <= x - 1;
end
if (right == 1'b1) begin
x <= x + 1;
end
end
end
endmodule
move.cpp
const char *help = "asdw: move | q: quit";
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <SDL2/SDL.h>
#include "Vmove.h"
#include "verilated.h"
#include "fps.hpp"
#define WINDOW_WIDTH 512
#define RECTS_PER_WINDOW (4)
#define RECT_WIDTH (WINDOW_WIDTH / RECTS_PER_WINDOW)
#define FASTEST_TICK_PERIOD_S (1.0 / 4.0)
int main(int argc, char **argv) {
SDL_Event event;
SDL_Renderer *renderer;
SDL_Window *window;
double current_time_s, last_tick_time_s;
unsigned int current_time, last_time;
const Uint8 *keystate;
Verilated::commandArgs(argc, argv);
Vmove *top = new Vmove;
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
SDL_SetWindowTitle(window, help);
fps_init();
top->clock = 0;
top->eval();
top->reset = 1;
top->clock = 1;
top->eval();
while (1) {
current_time = SDL_GetTicks();
current_time_s = current_time / 1000.0;
/* Deal with keyboard input. */
while (SDL_PollEvent(&event) == 1) {
if (event.type == SDL_QUIT) {
goto quit;
} else if (event.type == SDL_KEYDOWN) {
switch(event.key.keysym.sym) {
case SDLK_q:
goto quit;
default:
break;
}
}
}
keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_ESCAPE]) {
top->reset = 1;
}
if (keystate[SDL_SCANCODE_A]) {
top->left = 1;
}
if (keystate[SDL_SCANCODE_D]) {
top->right = 1;
}
if (keystate[SDL_SCANCODE_W]) {
top->up = 1;
}
if (keystate[SDL_SCANCODE_S]) {
top->down = 1;
}
if (current_time != last_time) {
if (current_time_s - last_tick_time_s > FASTEST_TICK_PERIOD_S) {
/* Draw world. */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
{
SDL_Rect rect;
rect.w = RECT_WIDTH;
rect.h = RECT_WIDTH;
rect.x = top->x * RECT_WIDTH;
rect.y = top->y * RECT_WIDTH;
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
SDL_RenderPresent(renderer);
top->clock = 0;
top->eval();
top->clock = 1;
top->eval();
top->up = 0;
top->down = 0;
top->left = 0;
top->right = 0;
top->reset = 0;
/* Update time tracking. */
last_tick_time_s = current_time_s;
fps_update_and_print();
}
}
last_time = current_time;
}
quit:
top->final();
delete top;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
display.cpp
/*
Test a simple virtual SDL display, without user input.
*/
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <SDL2/SDL.h>
#define WINDOW_WIDTH 600
#define WINDOW_HEIGHT (WINDOW_WIDTH)
#define N_PIXELS_WIDTH 10
#define N_PIXELS_HEIGHT (N_PIXELS_WIDTH)
#define N_PIXELS (N_PIXELS_WIDTH * N_PIXELS_HEIGHT)
#define PIXEL_WIDTH (WINDOW_WIDTH / N_PIXELS_WIDTH)
#define PIXEL_HEIGHT (WINDOW_HEIGHT / N_PIXELS_HEIGHT)
#define MAX_COLOR 255
#define PI2 (2*(acos(-1.0)))
#define FREQ (0.05)
int main(int argc, char **argv, char **env) {
SDL_Event event;
SDL_Rect rect;
SDL_Renderer *renderer;
SDL_Window *window;
const unsigned int max_color_half = MAX_COLOR / 2;
int quit;
double current_time_s;
size_t cur, i , j;
unsigned int
bs[N_PIXELS],
current_time,
gs[N_PIXELS],
last_time,
rs[N_PIXELS],
val
;
quit = 0;
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
rect.w = PIXEL_WIDTH;
rect.h = PIXEL_HEIGHT;
last_time = SDL_GetTicks();
while (!quit) {
while (SDL_PollEvent(&event) == 1) {
if (event.type == SDL_QUIT) {
quit = 1;
}
}
current_time = SDL_GetTicks();
if (current_time != last_time) {
for (i = 0; i < N_PIXELS_WIDTH; ++i) {
for (j = 0; j < N_PIXELS_WIDTH; ++j) {
cur = j * N_PIXELS_WIDTH + i;
val = (1 + i) * (1 + j) * PI2 * FREQ * current_time / 1000.0;
rs[cur] = max_color_half * (1.0 + std::sin(1 * val));
gs[cur] = max_color_half * (1.0 + std::sin(2 * val));
bs[cur] = max_color_half * (1.0 + std::sin(3 * val));
}
}
}
for (i = 0; i < N_PIXELS_WIDTH; ++i) {
for (j = 0; j < N_PIXELS_WIDTH; ++j) {
cur = j *N_PIXELS_WIDTH + i;
SDL_SetRenderDrawColor(renderer, rs[cur], gs[cur], bs[cur], 255);
rect.x = i * PIXEL_WIDTH;
rect.y = j * PIXEL_HEIGHT;
SDL_RenderFillRect(renderer, &rect);
}
}
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
GitHub upstream.
Connectal connects software running on actual CPUs to RTL (BSV, which can link to VHDL and Verilog) on FPGAs or simulators. BSV is free for academic and research use and for open source projects. In any case, Connectal is open source and the software to simulator connection uses SystemVerilog DPI, which you could use in your project without using BSV.
Connectal has one example that displays the output from the FGPA/simulator on a display. It uses Qt to display on the computer monitor when simulating. From an FPGA it displays directly on an HDMI display.
CPUs simulated in Verilog or VHDL tend to be too slow for interactive use, but I have connected a CPU simulated with qemu to devices or accelerators in verilator or on FPGA. Performance of qemu is quite good. I think it would work for your purposes.
I added a plugin FgpaOps API so that the simulator or FPGA could handle CPU load/store instructions:
struct FpgaOps {
uint64_t (*read)(hwaddr addr);
void (*write)(hwaddr addr, uint64_t value);
void (*close)(void);
void *(*alloc_mem)(size_t size);
};
In my case, I used connectal to implement the FpgaOps plugin. This code is under hw/riscv but is not specific to riscv, so it could be used with any processor architecture supported by qemu.
No need for anything too clever or customised to interact with your Sim providing you're willing to simulate a real hardware interface like a UART.
The Verilog simuation of my TTL CPU includes a (reasonably) accurate model of a UM245R UART and the UART supports interactive IO via the verilog file interface.
One file for input and the other for output; bidirectional.
I use this for interacting with the simualated hardware so that I can develop the software and test it via automated test without having to mess with the hardware.
I even have CHIP8 games running on the simulated hardware and the CHIP8 GUI is drawn by sending control codes from the UART back to a graphics terminal.
The UART is here ...
https://github.com/Johnlon/spam-1/blob/master/verilog/uart/um245r.v
At some point I'll do a write up on it.

SDCC integer comparison unexpected behavior

I'm trying to get started on a project using a PIC18F24J10. Attempting to use SDCC for this. At this point I've reduced my code to simply trying to nail down what is happening, as I've been seeing bizarre behavior for a while now and can't really proceed until I figure out what is going on. Not sure if this is my only problem at this point, but I have no idea why this is happening. Timer interrupt fires off, coupled with a #defined for loop causes LEDs on PORTC to blink maybe twice a second. If I just do a PORTC=0xFF and PORTC=0 this works fine. But it gets weird when I try to go much beyond that.
...
#define _RC0 31
#define _RC1 32
#define _RC2 33
#define _RC3 34
#define _RC4 35
#define _RC5 36
#define _RC6 37
#define _RC7 38
#define HI 1
#define LO 0
void why(unsigned char p, int z)
{
if(z == HI)
{
if(p == _RC0) PORTCbits.RC0 = 1;
else if(p == _RC1) PORTCbits.RC1 = 1;
else if(p == _RC2) PORTCbits.RC2 = 1;
else if(p == _RC3) PORTCbits.RC3 = 1;
else if(p == _RC4) PORTCbits.RC4 = 1;
else if(p == _RC5) PORTCbits.RC5 = 1;
else if(p == _RC6) PORTCbits.RC6 = 1;
else if(p == _RC7) PORTCbits.RC7 = 1;
}
else if(z == LO)
{
PORTC = 0b11110000;
}
else
{
PORTC = 0b10101010;
}
}
void timer_isr (void) __interrupt(1) __using (1)
{
TMR0H=0;
TMR0L=0;
why(_RC0, LO);
why(_RC1, LO);
why(_RC2, LO);
WAIT_CYCLES(5000);
why(_RC0, HI);
why(_RC1, HI);
why(_RC2, HI);
WAIT_CYCLES(5000);
}
void main(void)
{
WDTCONbits.SWDTE = 0;
WDTCONbits.SWDTEN = 0;
TRISC = 0b00000000;
PORTC=0b00000000;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.TMR0IF = 0;
INTCONbits.TMR0IE = 1;
T0CONbits.T08BIT = 0;
T0CONbits.T0CS = 0;
T0CONbits.PSA = 1;
TMR0H = 0;
TMR0L = 0;
T0CONbits.TMR0ON = 1;
while(1)
{
}
}
In the code above, four of the LEDs should blink, while the other four stay on. Instead, the LEDs stay on in the 10101010 pattern that happens in the "else" block, which should happen when "why" is called with any value other than HI or LO. I never call it with anything else, so why does it ever reach that?
UPDATE - Further reduction, no more interrupts or unspecified includes/defines. This is now the entirety of the program, and I am still seeing the same behavior. Changed the pattern from 10101010 to 10101011 so that I could verify the chip is actually being programmed with the new code, and it appears to be.
#include "pic16/pic18f24j10.h"
#define WAIT_CYCLES(A) for(__delay_cycle = 0;__delay_cycle < A;__delay_cycle++)
int __delay_cycle;
#define HI 1
#define LO 0
void why(int z)
{
if(z == HI)
{
PORTC = 0b11111111;
}
else if(z == LO)
{
PORTC = 0b11110000;
}
else
{
PORTC = 0b10101011;
}
}
void main(void)
{
TRISC = 0b00000000;
PORTC=0b00000000;
while(1)
{
why(LO);
WAIT_CYCLES(5000);
why(HI);
WAIT_CYCLES(5000);
}
}
Once the interrupt is asserted it is never cleared. That results in timer_isr() being called repeatedly. No other code is ever reached. The TMR0IF bit must be cleared in software by the Interrupt Service Routine.
Keep in mind you not only need to spend less time in the ISR than the period of the timer - it’s a good practice to spend the minimum amount of time necessary.
Remove the delays and simply toggle a flag or increment a register. In your main while (1) loop monitor the flag or counter and make your calls to why() from there.

pwm value not changing

I have written a pwm code for Atmega128. I am using fast pwm mode with non-inverting pulse on compare match and I need to change the OCR0 value at certain times. Yet it doesn't change. Anyone knows what is the problem here ??
#include <avr/interrupt.h>
#include <avr/io.h>
uint8_t tick_1sec;
void timer1_init(void) // 1 second timer
{
OCR1A = 15624;
TIMSK |= (1<<OCIE1A);
TCCR1B = (1<<WGM12); //CTC mode
TCCR1B |= (1<<CS12)|(0<<CS11)|(1<<CS10);
}
ISR(TIMER1_COMPA_vect) //1 second interrupt
{
cli();
tick_1sec = 1;
sei();
}
void timer0_init(void) // fast pwm with OC0 non-inverting mode
{
TCCR0 = (1<<FOC0)|(1<<WGM01)|(1<<WGM00);
TCCR0 |= (1<<COM01)|(0<<COM00);
TCCR0 |= (1<<CS02)|(1<<CS01)|(1<<CS00);
OCR0 = 63;
TIMSK |= (1<<OCIE0);
}
int main(void)
{
uint8_t t = 0;
DDRB = 0xFF;
timer0_init();
timer1_init();
sei();
while(1){
if (tick_1sec)
{
tick_1sec = 0;
t++;
if (t == 10){
OCR0 = 127;
}
else if (t == 20){
OCR0 = 191;
}
else if (t == 30){
OCR0 = 63;
t = 0;
}
}
}
return 0;
}
Things to check:
I recommend declaring tick_1sec as volatile to prevent the compiler of hyper-optimizing that register.
What is your clock frequency? Your ISR will deliver 1s calls only if your CPU frequency is 16MHz (==> 16.000.000 / 1024 / 15624)
You might have a LED in your hardware which you can invert from a) the ISR b) within the first if () in main to see if this is ever reached.
update: "volatile"
The link provided by #skyrift in his comment is very worth reading.
When you use Atmel Studio, compile your code once with/without the volatile keyword and compare what the compiler is doing ==> Solution explorer / Output Files / *.lss ... you will see each C statement and how the compiler converts it to machine code ... an exercise worth once in a while when working with micros ...

Resources