compiling error while declaring sfr address - c

i am working on a 8051 based MCU STC16C65A and i want it to emit PWM thru P2.0, sp i copy and modify this code from their manual:
#include "8051.h"
sfr AUXR = 0x8e;
//Auxiliary register T0 interrupt service routine
void t0int() interrupt 1 //(location at 000BH)
{
}
void main()
{
AUXR = 0x80;
//timer0 work in 1T mode
TMOD = 0x06; //set timer0 as counter mode2 (8-bit auto-reload)
TL0 = TH0 = 0xff; //fill with 0xff to count one time
TR0 = 1; //timer0 start run
ET0 = 1; //enable T0 interrupt
EA = 1; //open global interrupt switch
IF P2.0 = 0 THEN P2.0 = 1 ELSE P2.0 = 0;
while (1);
}
but when i compile it using MCU 8051 ide comes out a syntax error, declaration ignored in sfr AUXR = 0x8e; i think is that the library used (8051.reg) is a generic one instead of the reg51.h (oudated) that they suggest in the manual which i dont use because cames a error message of library out to date
Who can hep me? maybe i have to choose another adress for that pointer?
thanks in advance

SDCC is a different compiler than Keil C51, you have to expect differences in extensions to the C standard. And the declaration of SFRs is an extension.
Please use the documented syntax:
__sfr __at(0x8e) AUXR;

Related

Question about Peripheral Timing Generator (PTG) Module on dsPIC33CK256MP508

I am a newbie to programming in the Microchip PIC environment, so please excuse my naivete! I recently began experimenting with the dsPIC33CK Curiosity dev board (which contains the dsPIC33CK256MP508 dsp/mcu at its core), and have been exploring the on-board modules, like direct memory access (DMA) and the peripheral trigger generator (PTG).
DMA is working, but I am having trouble with a seemingly-simple PTG task, and I was wondering if anyone has any ideas -- the task involves a simple external interrupt/trigger to the PTG, which then needs to trigger another external pin to go logic-high.
In real life, an incoming logic-high signal will indicate the start of a series of analog data to be read, so the outgoing signal will (repeatedly) trigger an external ADC. I am using an external ADC (an ADS831, which I have working well) since the internal ADC in the dsPIC33 does not sample at the rates I need.
I am unsure if my mistake lies with my PTG commands, or if maybe my Peripheral Pin Select (PPS) module setup is flawed. Unfortunately, it appears that the builtin IO pin unlocking function ("__builtin_write_RPCON()") is undefined, at least with my included libraries. So, fell back on in-line assembler to perform the unlock sequence (detailed in datasheet DS70005349J-page 132).
Also strange: you'll notice I start my PTG sequence on "STEP3", though the PTG documentation (e.g., DS70000669B-page 33) advises starting at "STEP0". The reason I've done this is because "STEP1" and "STEP2" are apparently used by more than one Special Function Register (SFR). I discovered this in a support file included in my compiler directory (specifically, lines 26278 and 26281 of file "p33CK256MP508.h").
Anyway, here is my simple PTG-testbed code:
/* Testbed to explore the PTG module.
*
* File: newmain.c
* Author: benjamin sadler
*
* Created on January 26, 2023, 11:43 AM
*/
#include <xc.h>
/*
#define PTGCTRL(x) ((0x0 << 4) | ((x) & 0x0F)) // PTG command definitions
#define PTGWHI(x) ((0x4 << 4) | ((x) & 0x0F)) // from DS70000669B-page 15
#define PTGTRIG(x) ((0x4 << 5) | ((x) & 0x1F)) // (currently commented to
#define PTGJMPC0(x) ((0x6 << 5) | ((x) & 0x1F)) // try alternate commands
*/ // (see lines 58-60))
void init_PTG(void); // init function primitives
void init_PPS(void);
int main(int argc, char** argv) {
ANSELB = 0x0; // configure PORTB and PORTC
ANSELC = 0x0; // as digital, and set
TRISBbits.TRISB15 = 0; // direction bits:
TRISCbits.TRISC0 = 1; // B15->out, C0->in
init_PPS(); // initialize PPS
init_PTG(); // initialize PTG
PTGCSTbits.PTGSTRT = 1; // start PTG ...
while(1); // .. and wait for INT2->high.
return (1);
}
void init_PPS( void )
{
INTCON2bits.GIE = 1; // enable global interrupts
asm ("mov #0x55, w0"); // "__builtin_write_RPCON()"
asm ("mov w0, _NVMKEY"); // function doesn't appear
asm ("mov #0xAA, w0"); // to be defined, so in-line
asm ("mov w0, _NVMKEY"); // assembly needed unlock IOLOCK
RPCONbits.IOLOCK = 0; // (that is, set IOLOCK = 0)
_INT2R = 48; // PPS connect INT2 with RP48/PORTC0
asm ("mov #0x55, w0"); // more in-line assembly to
asm ("mov w0, _NVMKEY"); // re-lock IOLOCK ...
asm ("mov #0xAA, w0");
asm ("mov w0, _NVMKEY");
RPCONbits.IOLOCK = 1; // re-lock IOLOCK
}
void init_PTG( void )
{
PTGCON = 0; // most bits on PTGCST and
PTGCST = 0; // PTGCST registers should be
PTGCSTbits.PTGEN = 1; // zero, except PTGEN=1 which
// enables module
PTGQPTR = 3; // start at STEP3 (STEP1, STEP2
// aren't available??)
PTGC0LIM = 5; // loop 5 times back to STEP3
/* // set STEP commands:
_STEP3 = PTGWHI(15); // wait for INT2 interrupt
_STEP4 = PTGTRIG(25); // then trigger RP47/B14 high
_STEP5 = PTGJMPC0(3); // and jump back to STEP3
*/
_STEP3 = 0b01001111; // alternate try at setting
_STEP4 = 0b10011001; // PTG step commands, using
_STEP5 = 0b11000011; // data from Table 24-1 in
} // datasheet DS70005349J-page 478
And here are the results I'm getting:
Using the simulator (MPLAB X IDE v6.05, with xc16 compiler v2.00) with the correct device (dsPIC33CK256MP508) selected, this code will compile and run, but when I feed in a simulated RC0-> high with the Stimulus tool, I can see that PORTC0 goes high in the variable watch window, but the PTG-triggered output (on RP47/PORTB15) is never observed.
B15 stays low :(
You can also see I've tried programming the PTG steps both using the suggested bit-wise operators (currently commented out), as well as manually loading the bit fields.
I have worked on this for several days without any success, and now I humbly ask for help!

stm8 uart tx interrupt issue

I am programming a STM8S103F3 to TX on UART via interrupt. I understand a write to DR after "Transmit data register empty interrupt" will start another TX, so I have this in my ISR. But it only works if my main loop spins on wait for interrupt. If it spins on nop only the first char is TXed - as though the write to DR within the ISR does not generate a subsequent interrupt.
Using SDCC compiler.
sdcc -mstm8 -o build\uart.hex uart.c
#include <stdint.h>
#include <stdlib.h>
#include "stm8.h"
#define DEBUG_BUF_SIZE 10
char debugBuf[DEBUG_BUF_SIZE];
volatile unsigned char *debugPtr;
// UART Tx interrupt
void TX_complete(void) __interrupt(UART_TX_COMPLETE) {
if(*debugPtr != 0) {
UART1_DR = *debugPtr++;
}
}
void log(char *msg)
{
unsigned char i = 0;
UART1_CR2 &= ~UART_CR2_TIEN;
for(; msg[i] != 0 && i<DEBUG_BUF_SIZE-1; i++) {
debugBuf[i] = msg[i];
}
debugBuf[i] = 0;
debugPtr = debugBuf;
UART1_CR2 |= UART_CR2_TIEN;
// Write to DR will start tx
UART1_DR = *debugPtr++;
}
int main(void)
{
// UART 115K2 baud, interrupt driven tx
// UART1_CR1, UART_CR3 reset values are 8N1
UART1_BRR2 = 0x0B;
UART1_BRR1 = 0x08;
UART1_CR2 |= UART_CR2_TEN | UART_CR2_TIEN;
/* Set clock to full speed (16 Mhz) */
CLK_CKDIVR = 0;
log("Run\r\n");
while(1) {
// Only the first char is txed if nop is used
nop();
// But all chars txed if wfi is used
// wfi();
}
}
See your reference manual for stm8 (I use CD00218714) at chapter 12.9.1 you will see default value (after reset) of CPU condition code register it's 0x28 - this mean that just after start your mcu will work at interrupt level 3 and all software interrupt are disabled, only RESET and TRAP will workable.
According to program manual (I use CD00161709) instruction WFI change interrupt level to level 0 and your software interrupt of USART become workable.
You need to insert asm("rim"); just after initialization code (after line CLK_CKDIVR = 0;) - this will make your code workable with asm("nop"); based main loop.

I need to know why my interrupts are not working here

I am using stm8l - discovery and i have created a code for toggling a led for every 1 second using timer (TIM1) but this is not working properly. I am missing something here in my configuration
I could enter the interrupt function for the first time but after that it does not enter the interrupt function. Someone please look into and help me out
enter code here
#include <iostm8l.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defs.h"
unsigned int count = 0;
#svlreg #interrupt void TIM1(void)
{
count += 1;
TIM1_SR1 &= ~(0x01);
}
main()
{
CLK_DIVR = 0x00; // Set the frequency to 16Mhz
CLK_PCKENR2 = 0x02; // clock for timer1
PC_DDR = 0x80; // direction output for led
PC_CR1 = 0x80; // fast push pull mode
PE_DDR = 0x80; // direction output for led
PE_CR1 = 0x80; // fast push pull mode
TIM1_PSCRH = 0x3e; //to create a frequency for 1000 hz
TIM1_PSCRL = 0x80; // so prescalar is 16000
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
_asm("rim\n");
while(1)
{
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}
}
}
The interrupt enters only one time but after that it does not enter. So variable "count" remains at value 1
You are using magic numbers for the bit masks instead of defined constants, so the code is pretty damn hard to read for you and me both. Change this so that the code ends up like for example
TIM1_SR1 &= ~TIM1_SR1_UIF;
Since this is a 8 bit MCU it is also absolutely essential that you u suffix all integer contants, or they will be of type signed int, which you don't want.
For example this code TIM1_SR1 &= ~(0x01); is equivalent to TIM1_SR1 &= -2. Very easy to write accidental subtle bugs this way. I recommend studying Implicit type promotion rules.
It is highly recommended to disassemble every ISR you write to see what machine code you actually end up with, and single step it through the debugger while watching the register as well. This particular register seems to ignore having 1 written to it, so you could probably just do TIM1_SR = TIM1_SR1_UIF;. Incorrectly cleared timer flags inside ISRs is one of the most common bugs in embedded systems.
Quoting the manual:
UIF: Update interrupt flag
– At overflow or underflow if UDIS = 0 in the TIM1_CR1 register
– When CNT is re-initialized by software using the UG bit in TIM1_EGR register, if URS = 0 and UDIS = 0 in the TIM1_CR1 register.
– When CNT is re-initialized by a trigger event (refer to the TIM1_SMCR register description), if URS = 0 and UDIS = 0 in the TIM1_CR1 register
Your code doesn't appear to do any of this, so it is pretty safe to assume the timer counter isn't reset.
Another problem is that count must be declared as volatile or otherwise the compiler might optimize out this code completely:
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}

Interrupt-driven USART using UDRE with ATmega328P

I am having a problem with programming the serial for Arduino in C. The application demands speed, so I need to do it in C. I am using Codeblocks for it as it is easy to compile.
As I also want the serial feature not blocking the application and giving debug capability, I am trying to write a circular buffer type of serial library. The application does not need to receive data, only print.
The problem begins with the serial interrupt apparently not firing and the program blocks, the compiler does give a warning:
main.c|11|warning: ‘UART_UDRE_vect’ appears to be a misspelled signal handler|
The test program is as follows:
#include<avr/io.h>
#include<avr/interrupt.h>
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU/(USART_BAUDRATE*16UL)))-1)
char ok = 0;
ISR(UART_UDRE_vect) {
ok = 1;
UCSR0B &= ~(1<<5);
}
int main(void) {
UBRR0H = (BAUD_PRESCALE >> 8);
UBRR0L = BAUD_PRESCALE;
UCSR0B |= (1<<TXEN0);
UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
sei();
while(1){
// write the byte to the serial port
UDR0 = '0';
UCSR0B |= (1<<5);
while(ok != 1){}
ok = 0;
UDR0 = '\n';
UCSR0B |= (1<<5);
while(ok != 1){}
ok = 0;
}
return 0;
}
The configuration and baud rates are correct because the echo example found here does work.
Also other examples does not use UDRE, only RX interruption and that is not what I am looking for.
Am I forgetting something?
Two problems:
According to the documentation you linked, the interrupt vector for your particular part ATmega328p should be named USART_UDRE_vect.
Variables shared with an interrupt must always be declared as volatile or the compiler might not understand that they are used and therefore break your program upon optimization. Basically the compiler thinks that the variable ok can never get another value than 0, since it doesn't see a function call to the ISR anywhere (since it is called by hardware, not by the program). Change the declaration to static volatile char ok;

How do you write and read to memory with PIC18?

I want to store a number to PIC18 then retain it even if the power is lost or the unit is reset. I think my writing code portion looks fine, just the reading portion of it looks strange after the unit is reset.
I am using the following code which I got from Microchip.
Code:
unsigned int value;
unsigned int DEEdata = 1;
unsigned int DEEaddr = 0x04;
DataEEInit();
dataEEFlags.val = 0;
DataEEWrite(DEEdata,DEEaddr);
value = DataEERead(DEEaddr);
Nop();
printf("%d",value);
The ouput: 1
However when I reset the unit and only use the reading code I always get 255.
Code to read:
DataEEInit();
value = DataEERead(DEEaddr);
printf("%d",value);
The output: 255
Why is this happening? I am assuming maybe the value is not being saved or the reading portion is incorrect. Thank you!
Two functions: write to flash using 64-byte buffer # 8-byte blocks and a read/compare flash function.
For device: PIC18F46K80
Stuff for a header file:
#define PRGM_BUFFER_SIZE 8
#define TABLE_WRITE_SIZE 64
#define LOAD_TBL_PTR(x) { TBLPTRU = ((((x)>>8)>>8)&0xff);\
TBLPTRH = (((x) >> 8) & 0xff);\
TBLPTRL = ((x) & 0xff);\
}
Write to flash function:
/******************************************************
* Function : write_block
* Input : uint16_t position in destination flash
* Global : uint8_t buffer[64] - Location of source data
* Output : None
* Description : Writes the contents of the 64 byte
* data buffer to program flash space. Only 64 bytes
* can be written at once. The process of writing
* to flash is: Erase->Write.
******************************************************/
static void write_block(uint16_t addr)
{
int r, c;
// Erase flash block first. Erases a 64 byte block at a time.
LOAD_TBL_PTR(addr);
EECON1bits.EEPGD = 1; // Point to flash program memory
EECON1bits.CFGS = 0; // Access flash memory
EECON1bits.WREN = 1; // Enable write to memory
EECON1bits.FREE = 1; // Enable Erase operation
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // Clear the flash
asm("NOP"); // Stall
// Write buffer to internal buffer. This process writes 8 bytes at a time
// so we need to loop 8 times (8*8 = 64).)
for (r = 0; r < 8; r++)
{
LOAD_TBL_PTR((addr + (r * 8)));
for (c = 0; c < PRGM_BUFFER_SIZE; c++)
{
TABLAT = buffer[(r * 8) + c];
asm("TBLWT*+"); // Push byte and then inc to next internal buffer cell
}
// Write the block to flash
asm("TBLRD*-"); // Point back to original row
// Write internal buffer to flash
EECON1bits.EEPGD = 1; // Point to flash program memory
EECON1bits.CFGS = 0; // Access flash program memory
EECON1bits.WREN = 1; // Enable write to memory
INTCONbits.GIE = 0; // Disable interrupts
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // Start programming flash
INTCONbits.GIE = 1; // Re-enable interrupts
EECON1bits.WREN = 0; // Disable write to memory
}
}
Verify written data (demonstrates flash read)
/******************************************************
* Function : compare_block
* Input : uint16_t position in destination flash
* Global : uint8_t buffer[64] - Location of previous written data
* Output : bool true=successful, false=did not match
* Description : Reads a 64 byte block of flash memory and
* compares it to the data found in the global buffer.
******************************************************/
static bool compare_block(uint16_t addr)
{
bool retVal = true; // succeeds
uint8_t i = 0;
INTCONbits.GIE = 0; // Disable interrupts
LOAD_TBL_PTR(addr);
for (i = 0; i < TABLE_WRITE_SIZE && retVal == true; i++)
{
asm("TBLRD*+");
if (buffer[i] != TABLAT)
retVal = false;
}
INTCONbits.GIE = 1; // Enable interrupts
return retVal;
}
Yours,
Bryan Wilcutt
The device you're using doesn't have internal non-volatile memory apart from its Flash, generally used for storing code.
You have two options that I can see:
Use some external Flash or EEPROM and interface it to the External Memory Bus that's available on this PIC (see page 97 of the Family Datasheet).
Remap the internal Flash to reserve a small portion that can be used for storing your data (so that it doesn't interfere with the memory area used exclusively for code) and write your data into this region (page 87).
I haven't worked with PICs for years, so can't offer you much in the way of implementation detail but I suspect there are many examples you can source from Microchip's website.
In essence, the reason your code doesn't work is because you're trying to access memory that isn't there. If it is there, then the interface is not correct.
EDIT:
I've had a look through the code examples page for the PIC18 on Microchip's website and can't find any C examples for writing to the program memory. Unfortunately, it looks like you'll have to implement it in assembler. I don't know the semantics for the MPLAB compiler but, generally, it'll be something like this if you're going to do it inline:
void my_assembler_function(void)
{
// Inline assembler code, actioned via C.
asm("MOV x y");
asm("MOV y z");
}
Alternatively, many C compilers for microprocessor's allow you to call an external .s file with a C function call, saving you from doing it inline.
I think you can follow the example I found here to actually implement the functionality you're after.
SRAM can not be used to store Non-volatile data...
SRAM will loose data during power cycle...
Options:
1. Use internal EEPROM if available.
2. External EEPROM through I2C or SPI.
3. PIC18 Data Emulation Library.
This is an explanation of the PIC18:
/* EEPROM Read and Write Functions -- WORKING
* Used PIC18F45K22 and MPLAB and C18
* Read and Write functions work.
* EEPROM has 256 bytes of memory (256 distinct characters)
* Select "Window" -> "PIC Memory Views" -> "EE Data Memory"
* Download program to PIC18
* Hold PIC in Reset (circle arrow with pause button)
* Open EE Data Memory Tab and click "Read Device Memory" button (Top left of EE Data tab) while PIC is held in Reset
*/
This is helpful code:
#include <p18cxxx.h>
#include <p18f45k22.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#pragma config FOSC = INTIO67, PLLCFG = OFF, PRICLKEN = ON, FCMEN = ON, PWRTEN = OFF
#pragma config BOREN = SBORDIS, BORV = 250, WDTEN = OFF, WDTPS = 2048, PBADEN = OFF, WRTD = OFF
#pragma config HFOFST = OFF, MCLRE = EXTMCLR, STVREN = ON, LVP = OFF, DEBUG = ON, CPD = OFF
void EE_Write(unsigned char addr, unsigned char value);
unsigned char EE_Read(unsigned char addr);
unsigned char test;
void main(void){
OSCTUNEbits.PLLEN = 1;
OSCCON = 0x4C; //Set to use internal clock.
OSCCON2 = 0x00; // No 4x PLL
TRISB = 0x00;
ANSELB = 0x00;
PORTB = 0x00;
EE_Write(05, 0x5A);
Delay10KTCYx(50);
test = EE_Read(05);
Delay10KTCYx(50);
PORTB = 0xFF;
Delay10KTCYx(50);
PORTB = 0x00;
}
void EE_Write(unsigned char addr, unsigned char value)
{
unsigned char SaveGIE = 0;
// Set EEPROM address
EEADR = addr%256;
// Set EEPROM data
EEDATA = value;
// Select Data
EECON1bits.EEPGD = 0;
// Select EEPROM
EECON1bits.CFGS = 0;
// Enable write
EECON1bits.WREN = 1;
// Save current global interrupt enable state
SaveGIE = INTCONbits.GIE;
// Disable interrupts
INTCONbits.GIE = 0;
// Write unlock sequence
EECON2 = 0x55;
EECON2 = 0xaa;
// Start write
EECON1bits.WR = 1;
// Restore previous interrupts enable state
INTCONbits.GIE = SaveGIE;
// Wait for write completion
while(EECON1bits.WR);
// Disable writes
EECON1bits.WREN = 0;
}
unsigned char EE_Read(unsigned char addr){
while(EECON1bits.RD || EECON1bits.WR); // check the WR&RD bit to see if a RD/WR is in progress
EEADR = addr; // Write the address to EEADR.
EECON1bits.CFGS = 0;
EECON1bits.EEPGD = 0;
EECON1bits.RD = 1; // Set the RD bit to trigger the eeprom read operation.
return(EEDATA);
}
Some PIC18 micros have an internal EEPROM in addition to the internal flash. The 18F87J11 does not have this so you have 2 options:
1) Write to the flash memory - this is where your program is stored. make sure the number of write/read cycles is ok for your application.
2) Use an external i2c or spi memory for your configuration settings
The DataEEWrite you are using are from an 'eeprom emulation' library from microchip (linked in the comments below. There are a couple of things to be careful of:
Watch out when reprogramming the flash! you might overwrite your settings
Remember it isn't really eeprom! The write cycles are limited and you have to erase big sections of memory - you can't erase a single byte
The value of 255 is default value for EEPROM memory. I think after changing the code, you program microcontroller IC again. So, your EEPROM memory will be erased and return to its default value. If you use MPLAB as compiler, you can go to 'Programmer'tab > Settings.. > Program Memory > Program Options and click on Preserve EEPROM on Program.
Hope it works.
To retain the values on power cycle, SRAM memory should be used. Please confirm if you have SRAM memory available first.

Resources