I could not found an answer with google so i went for it and programmed quite a few hours.
I want to save 9-bit values to eeprom without wasting the other 7 bits.
I save values that would be up to 500 and i have not much EEPROM left.
The same principle can be applied to arrays, which i did just to not waer down the EEPROM.
So I made this little program:
/*
* Write only a certain number of bits to EEPROM.
*
* keeps the other bit in the byte of the eeprom as they are.
*
* Working version with 9 bits:
* 2019-10-03 15:57
* 2019-10-03 22:09 tested with chars too
* 2019-10-04 08:25 works with 7 bit chars also!
* 2019-10-04 12:27 fixed the combining of oldByte and new values in writeBitsToEEPROM(), because chars like 'ö' altered previous bit (left side) that should not have been altered.
*
*/
#include "arduino.h"
#include "EEPROM.h"
#include "math.h"
#define BIT_BLOCKS_COUNT 15
#define BLOCK_BYTE_COUNT 17
#define ARRAY_SIZE BLOCK_BYTE_COUNT+2
//TODO: change back to original value
#define EEPROM_SIZE ARRAY_SIZE
byte fakeEEPROM[ARRAY_SIZE] = {0};
String byteToString(byte value){
char byteChar[9];
byteChar[8] = '\0'; //we need a terminator
for(int i=7; i>=0; i--){
byteChar[7-i] = (value & (1 << i)) ? '1' : '0';
}
return String(byteChar);
}
String byteToString(unsigned long value, byte bytesToRead){
String str1 = byteToString(value >> 8);
String str2 = byteToString(value & 0xFF);
return str1 + " " + str2;
}
int globBlockStartAdress = 0;
byte globNumberOfBits = 0;
int globBlockSizeBytes = 0;
bool initBitBlock(int blockStartAdress, int blockCount, byte numberOfBits) {
globBlockStartAdress = blockStartAdress;
globNumberOfBits = numberOfBits;
// calc needed number of bytes and roud up
int tempBlockSize = blockCount * numberOfBits / 8;
if(blockCount * numberOfBits % 8)
tempBlockSize++;
// make number of bytes even
if(tempBlockSize % 2)
tempBlockSize++;
globBlockSizeBytes = tempBlockSize;
if(blockStartAdress + globBlockSizeBytes > EEPROM_SIZE)
return false;
return true;
}
/*
* Writes 1 to 9 bits to "internalAdress" within a designated block in eeprom
*/
void writeBitsToEEPROM(unsigned int bitsToBeWritten, int internalAdress){
//TODO: check if value is not higher than what can be stored
// if(bitsToBeWritten){
//
// }
int trueEEPROMAdress = globBlockStartAdress + internalAdress * globNumberOfBits / 8;
if(trueEEPROMAdress + 1 >= ARRAY_SIZE || internalAdress * globNumberOfBits / 8 >= globBlockSizeBytes){
Serial.print("globBlockSizeBytes: ");
Serial.println(globBlockSizeBytes);
Serial.println("FEHLER writeBitsToEEPROMWTF: ");
Serial.println(trueEEPROMAdress + 1);
Serial.println(internalAdress * globNumberOfBits / 8 );
}
byte startBitOfEEPROMByte = (internalAdress * globNumberOfBits) % 8;
unsigned int oldIntFromEEPROM = (fakeEEPROM[trueEEPROMAdress] << 8) | fakeEEPROM[trueEEPROMAdress + 1];
//Todo: change to eeprom
//filter out only the bits that need to be kept.
//EEPROM.get(trueEEPROMAdress, oldEEPROMByteBits);
// there might be bits in the byte that we dont want to change. left side and right side
unsigned int mask1KeepFromEEPROM = (0xFFFF << (16 - startBitOfEEPROMByte));
unsigned int mask2KeepFromEEPROM = (0xFFFF >> (startBitOfEEPROMByte + globNumberOfBits));
//if(16 - startBitOfEEPROMByte - numberOfBits > 0)
//mask2KeepFromEEPROM= (0xFFFF >> (startBitOfEEPROMByte + numberOfBits));
// masks combined
unsigned int maskIntToKeepFromEEPROM = mask1KeepFromEEPROM | mask2KeepFromEEPROM;
int newEEPROMInt = (oldIntFromEEPROM & maskIntToKeepFromEEPROM) | ((bitsToBeWritten << (16 - globNumberOfBits - startBitOfEEPROMByte) & ~maskIntToKeepFromEEPROM));
//Todo: change to eeprom
//write
//EEPROM.update(trueEEPROMAdress, newEEPROMByteBitsA);
fakeEEPROM[trueEEPROMAdress] = (newEEPROMInt >> 8);
fakeEEPROM[trueEEPROMAdress + 1] = (byte) newEEPROMInt;
if(trueEEPROMAdress + 1 > BLOCK_BYTE_COUNT){
Serial.println("FEHLER writeBitsToEEPROM");
Serial.println(trueEEPROMAdress + 1);
Serial.println("blockStartAdress");
Serial.println(globBlockStartAdress);
Serial.println("internalAdress");
Serial.println(internalAdress);
Serial.println("numberOfBits");
Serial.println(globNumberOfBits);
}
// Serial.print("trueEEPROMAdress: ");
// Serial.println(trueEEPROMAdress);
//
// Serial.print("internalAdress: ");
// Serial.println(internalAdress);
//
// Serial.print("globNumberOfBits: ");
// Serial.println(globNumberOfBits);
//
// Serial.print("bitsToBeWritten: ");
// Serial.println(byteToString(bitsToBeWritten,2));
//
// Serial.print(" mask1KeepFromEEPROM: ");
// Serial.println(byteToString(mask1KeepFromEEPROM,2));
//
// Serial.print("mask2KeepFromEEPROM: ");
// Serial.println(byteToString(mask2KeepFromEEPROM,2));
//
// Serial.print("maskIntToKeepFromEEPROM: ");
// Serial.println(byteToString(maskIntToKeepFromEEPROM,2));
//
// Serial.print("oldIntFromEEPROM: ");
// Serial.println(byteToString(oldIntFromEEPROM,2));
//
// Serial.print("newEEPROMInt: ");
// Serial.println(byteToString(newEEPROMInt,2));
//
// Serial.print("512: ");
// Serial.println(byteToString(512, 2));
//
// Serial.print("65535: ");
// Serial.println(byteToString(65535, 2));
}
unsigned int ReadBitsFromEEPROM(int internalAdress){
int trueEEPROMAdress = globBlockStartAdress + internalAdress * globNumberOfBits / 8;
byte startBitOfEEPROMByte = (internalAdress * globNumberOfBits) % 8;
if(trueEEPROMAdress + 1 > BLOCK_BYTE_COUNT)
Serial.println("FEHLER readBits");
unsigned int oldIntFromEEPROM = (fakeEEPROM[trueEEPROMAdress] << 8) | fakeEEPROM[trueEEPROMAdress + 1];
//Todo: change to eeprom
//filter out only the bits that need to be kept.
//EEPROM.get(trueEEPROMAdress, oldEEPROMByteBits);
unsigned int mask1KeepFromEEPROM = (0xFFFF << (16 - startBitOfEEPROMByte));
unsigned int mask2KeepFromEEPROM = (0xFFFF >> (startBitOfEEPROMByte + globNumberOfBits));
unsigned int maskIntToKeepFromEEPROM = mask1KeepFromEEPROM | mask2KeepFromEEPROM;
unsigned int valueFromEEPROM = ~maskIntToKeepFromEEPROM & oldIntFromEEPROM;
// Serial.print("trueEEPROMAdress: ");
// Serial.println(trueEEPROMAdress);
//
// Serial.print("internalAdress: ");
// Serial.println(internalAdress);
//
// Serial.print("numberOfBits: ");
// Serial.println(numberOfBits);
//
// Serial.print(" mask1KeepFromEEPROM: ");
// Serial.println(byteToString(mask1KeepFromEEPROM,2));
//
// Serial.print("mask2KeepFromEEPROM: ");
// Serial.println(byteToString(mask2KeepFromEEPROM,2));
////
// Serial.print("maskIntToKeepFromEEPROM: ");
// Serial.println(byteToString(maskIntToKeepFromEEPROM,2));
////
// Serial.print("oldIntFromEEPROM: ");
// Serial.println(byteToString(oldIntFromEEPROM,2));
return (valueFromEEPROM >> (16 - globNumberOfBits - startBitOfEEPROMByte));
}
void setup() {
Serial.begin(57600);
Serial.print(F("\n# Programversion: "));
Serial.print(__TIME__);
Serial.print(" ");
Serial.println(__DATE__);
Serial.println("Setup finished");
delay(1000);
}
void printEEPROM(){
for(int i = 0; i < ARRAY_SIZE; i++){
byte b;
//Todo: change to eeprom
//EEPROM.get(i, b);
b = fakeEEPROM[i];
Serial.print(byteToString(b));
Serial.print(" ");
}
Serial.println();
}
void testNumbers() {
Serial.println("bits?");
while( ! Serial.available());
String input = Serial.readString();
unsigned int value = input.toInt();
initBitBlock(1, 15, 9);
// Serial.print("value: ");
// Serial.println(byteToString(value));
for(int i = 0; i < BIT_BLOCKS_COUNT;i++){
for(int j = 0; j < BLOCK_BYTE_COUNT; j++){
fakeEEPROM[j] = 0xFF;
if(j > BLOCK_BYTE_COUNT)
Serial.println("FEHLER testNumbers");
}
// Serial.print("EEPROM before: ");
// printEEPROM();
writeBitsToEEPROM(value, i);
Serial.print("Returned: ");
Serial.println(ReadBitsFromEEPROM(i));
// Serial.print("EEPROM after: ");
// printEEPROM();
// Serial.println();
}
delay(1000);
}
#define CHAR_COUNT 16
void testChars() {
// Serial.println("bits?");
// while( ! Serial.available());
// String input = Serial.readString();
//
// unsigned int value = input.toInt();
initBitBlock(1, CHAR_COUNT, 7);
Serial.println("string?");
while( ! Serial.available());
String input = Serial.readString();
Serial.println(input);
char testString[CHAR_COUNT] = {'\0'};
input.toCharArray(testString, CHAR_COUNT, 0);
for(int j = 0; j < ARRAY_SIZE; j++){
fakeEEPROM[j] = 0;//xFF;
}
for(int i = 0; i < CHAR_COUNT; i++){
Serial.print("EEPROM before: ");
printEEPROM();
writeBitsToEEPROM(testString[i], i);
Serial.print("EEPROM after: ");
printEEPROM();
Serial.println();
}
Serial.println("Returned: ");
for(int i = 0; i < CHAR_COUNT; i++){
Serial.print((char) ReadBitsFromEEPROM(i));
}
Serial.println();
delay(1000);
}
void loop(){
testChars();
testNumbers();
}
which of course it not complete. Its just for saving those 9-bit values.
My question is: Has anyone else programmed a function like this - or knows where to find this - that is not limited to 9 bits (10 bits will span over 3 bytes)?
This function should take the number of bits given by bitsPerVal from each value in the input array pVals and pack them into the byte array pointed to by pOutBytes:
#include <stdint.h>
void pack_bits(uint32_t *pVals, size_t numVals, int bitsPerVal, uint8_t *pOutBytes)
{
uint32_t mask = ~(UINT32_MAX << bitsPerVal);
int outBitsLeft = 8;
int inBitsLeft = bitsPerVal;
while(numVals > 0)
{
if(inBitsLeft > outBitsLeft)
{
inBitsLeft -= outBitsLeft;
*pOutBytes |= (*pVals & mask) >> inBitsLeft;
mask >>= outBitsLeft;
outBitsLeft = 0;
}
else
{
outBitsLeft -= inBitsLeft;
*pOutBytes |= (*pVals & mask) << outBitsLeft;
mask = ~(UINT32_MAX << bitsPerVal);
inBitsLeft = bitsPerVal;
--numVals;
++pVals;
}
if(0 == outBitsLeft)
{
outBitsLeft = 8;
++pOutBytes;
}
}
}
The array pointed to by pOutBytes must suitably sized (ie ((numVals*bitsPerVal) + 7) / 8) and initialised to zero before calling. You can write it to your EEPROM after.
Hopefully this works well, I have done much testing on it though.
Here is an example of how 10 bits (actually 16-bits when written...) from 2 different fields could write to 16-bits of output.
struct EEPROM_Output
{
uint16_t a : 9; // 0 - 511 can be stored here
uint16_t b : 1; // 0 or 1 here.
uint16_t pad : 6; // Future use - we place this here to make it obvious that there are bits remaining.
};
void foo()
{
struct EEPROM_Output save;
save.a = 100;
save.b = 1;
WriteToEEPROM(&save, sizeof(save));
}
I'm trying to run the following code in c on a beaglebone black (microcontroller running Debian).
The code compiles but terminates right when the pwm_init() function is called.
No printf will execute after this line, even the first in the pwm_init() function.
I tried removing pwm_init(), and then wait_for_pwm() will run normally.
This is a code to setup an interrupt timer on the beaglebone in order to communicate with a DAC through SPI.
The code was running and could communicate before this adding.
/*
*Filename: mems.c
*SPI test program to communicate with AD5666 DAC on Micro Mirror Driver board */
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "iolib.h"
#include <unistd.h>
#define DELAY_NS 62500 // Timer period in ns
// PRU Interrupt control registers
#define PRU_INTC 0x00020000 // Start of PRU INTC registers TRM 4.3.1.2
#define PRU_INTC_GER ((volatile uint32_t *)(PRU_INTC + 0x10)) // Global Interrupt Enable, TRM 4.5.3.3
#define PRU_INTC_SICR ((volatile uint32_t *)(PRU_INTC + 0x24)) // Interrupt, TRM 4.5.3.6
#define PRU_INTC_GPIR ((volatile uint32_t *)(PRU_INTC + 0x80)) // Interrupt, TRM 4.5.3.11
// PRU ECAP control registers (i.e. PWM used as a timer)
#define ECAP 0x00030000 // ECAP0 offset, TRM 4.3.1.2
// Using APWM mode (TRM 15.3.2.1) to get timer (TRM 15.3.3.5.1)
#define ECAP_TSCTR ((volatile uint32_t *)(ECAP + 0x00)) // 32-bit counter register, TRM 15.3.4.1.1
#define ECAP_APRD ((volatile uint32_t *)(ECAP + 0x10)) // Period shadow, TRM 15.3.4.1.5, aka CAP3
#define ECAP_ECCTL2 ((volatile uint32_t *)(ECAP + 0x2a)) // Control 2, TRM 15.3.4.1.8
#define ECAP_ECEINT ((volatile uint16_t *)(ECAP + 0x2c)) // Enable interrupt, TRM 15.3.4.1.9
#define ECAP_ECCLR ((volatile uint16_t *)(ECAP + 0x30)) // Clear flags, TRM 15.3.4.1.11
// R30 is the GPIO register
// R31 is the interrupt register
#define NUMBER_OF_COEFS 87
int xn[NUMBER_OF_COEFS] = { 0 };
int ynn[NUMBER_OF_COEFS] = { 0 };
int xy[2];
static double coefs[NUMBER_OF_COEFS] = { -0.003874396983162784,-0.0037425007502381417,0.0007168162935488041,-0.0015837981969284466,0.001324731958160302,0.000940030114550933,0.002909179571989647,0.002970492669088027,0.0037475240063036684,0.003135242276391628,0.002431551570668268,0.0007465565198417194,-0.0010918847362976609,-0.0032610680167253635,-0.0050886443383995035,-0.0064219306251743396,-0.0067757336585719885,-0.00603689840577871,-0.004073405037328031,-0.001084864753089533,0.002607744624181485,0.006446336960328277,0.009805149887731802,0.012005211009068262,0.01248315933178856,0.010855477027307714,0.007038206816858291,0.0013011753812607633,-0.005726736257811221,-0.013085733616184817,-0.019608024169477135,-0.024024160014903175,-0.025137566107801428,-0.022018671074884637,-0.01412798218138592,-0.0014477915111131118,0.015482420337480308,0.03556527369143834,0.057256428960766804,0.07871540989639365,0.09799912606296178,0.1132905004893123,0.12311069228747347,0.1265004803246064,0.12311069228747347,0.1132905004893123,0.09799912606296178,0.07871540989639365,0.057256428960766804,0.03556527369143834,0.015482420337480308,-0.0014477915111131118,-0.01412798218138592,-0.022018671074884637,-0.025137566107801428,-0.024024160014903175,-0.019608024169477135,-0.013085733616184817,-0.005726736257811221,0.0013011753812607633,0.007038206816858291,0.010855477027307714,0.01248315933178856,0.012005211009068262,0.009805149887731802,0.006446336960328277,0.002607744624181485,-0.001084864753089533,-0.004073405037328031,-0.00603689840577871,-0.0067757336585719885,-0.0064219306251743396,-0.0050886443383995035,-0.0032610680167253635,-0.0010918847362976609,0.0007465565198417194,0.002431551570668268,0.003135242276391628,0.0037475240063036684,0.002970492669088027,0.002909179571989647,0.000940030114550933,0.001324731958160302,-0.0015837981969284466,0.0007168162935488041,-0.0037425007502381417,-0.003874396983162784};
#define REF_ON 0x01000008 //command to turn on internal VREF
#define X_OFFSET 3
#define Y_OFFSET 0
#define X_DRIVE 1
#define Y_DRIVE 2
#define SIZEMAT 2
float tabx[SIZEMAT] = { -100, 100 };
float taby[SIZEMAT] = { -100, 100 };
// Forward definitions
int convert_spi(int dac_val,int channel); //formats bytes for write function
inline void pwm_init();
inline void wait_for_pwm_timer();
int* fir_filterXY(int x, int y);
int main(int argc, char **argv){
int i, fd, debug=0, loop=0, user_loop=0;
int x_off=-1, y_off=-1;
int x_val=-1, y_val=-1;
int freq = -1;
unsigned int buf = REF_ON;
unsigned int dac_value = 1; // 0 to 65535 value to set dac output
unsigned int spi_bytes = 0; // spi communication bytes to send
char direction = 0; // Direction of triangle wave ramp
fd = open("/dev/spidev1.0", O_RDWR);
if(fd < 0) printf("spi failed to open\n");
iolib_init();
//Set LDAC control pin to output
iolib_setdir(9,15,1);
//Tying LDAC low will update dac channel as soon as it has new data
pin_low(9,15); //sel0
write(fd,&buf,4); //set internal vref on
// User loop
int valx = 0;
int valy = 0;
int* ass;
int assx = 0;
int assy = 0;
int i = 0;
int freqcnt = 0;
int freqi = 0;
if (freq>1000)
{
freq = 1000;
}
if (freq<1)
{
freq = 1;
}
freqcnt = (int)((1000000000/DELAY_NS)/freq - 1);
spi_bytes = convert_spi(32000, X_OFFSET);//format bytes for write function
write(fd, &spi_bytes, 4);
spi_bytes = convert_spi(32000, Y_OFFSET);//format bytes for write function
write(fd, &spi_bytes, 4);
printf("In user loop with movement frequency of:%i\n", freq);
pwm_init();
valx = 32000;
valy = 32000;
assx = 32000;
assy = 32000;
printf("starting\n");
while (1){
wait_for_pwm_timer();
spi_bytes = convert_spi(assx, X_DRIVE);//format bytes for write function
write(fd, &spi_bytes, 4);
spi_bytes = convert_spi(assy, Y_DRIVE);//format bytes for write function
write(fd, &spi_bytes, 4);
freqi++;
if(freqi >= freqcnt){
valx = (int)((tabx[i]+100) * 320);
valy = (int)((taby[i]+100) * 320);
freqi = 0;
i++;
if (i >= SIZEMAT)
i = 0;
}
ass = fir_filterXY(valx, valy);
assx = *(ass);
assy = *(ass+1);
}
return 0;
}
/* Function: convert_spi
*
* Takes a dac value (0-65535) and a dac channel (or all channels) and generates the appropriate 32bits to send to AD5666 via SPI
*
* INPUTS
* dac_val: sets the voltage output with voltage output= 2.5*(dac_val/65535)
* channel: selects which dac channel to update with dac_val. 0=DACA ,1=DACB, 2=DACC, 3=DACD, 16=all
*
* RETURNS
* spi_data: integer value to send via spi using to update channel with new dac value
*/
int convert_spi(int dac_val,int channel){
int spi_data=0;
unsigned int nibble1;
unsigned int nibble2;
unsigned int nibble3;
unsigned int nibble4;
nibble1= dac_val & 0xF000;
nibble2= dac_val & 0x0F00;
nibble3= dac_val & 0x00F0;
nibble4= dac_val & 0x000F;
spi_data |=(nibble1>>4);
spi_data |=(nibble2<<12);
spi_data |=(nibble3<<12);
spi_data |=(nibble4<<28);
spi_data |=(channel<<12);
return spi_data;
}
// Initializes the PWM timer, used to control output transitions.
// Every DELAY_NS nanoseconds, interrupt 15 will fire
inline void pwm_init(){
printf("Intereupt setup");
*PRU_INTC_GER = 1; // Enable global interrupts
printf("1");
*ECAP_APRD = DELAY_NS / 5 - 1; // Set the period in cycles of 5 ns
printf("2");
*ECAP_ECCTL2 = (1<<9) /* APWM */ | (1<<4) /* counting */;
printf("3");
*ECAP_TSCTR = 0; // Clear counter
printf("4");
*ECAP_ECEINT = 0x80; // Enable compare equal interrupt
printf("5");
*ECAP_ECCLR = 0xff; // Clear interrupt flags
printf("done\n");
}
// Wait for the PWM timer to fire.
// see TRM 15.2.4.26x
inline void wait_for_pwm_timer() {
register unsigned int __R31;
while (!(__R31 & (1 << 30))) {} // Wait for timer compare interrupt
*PRU_INTC_SICR = 15; // Clear interrupt
*ECAP_ECCLR = 0xff; // Clear interrupt flags
}
int* fir_filterXY(int x, int y){
int i = 0;
double temp = 0;
for (i = 0; i < NUMBER_OF_COEFS - 1; i++)
{
xn[i] = xn[i + 1]; //xn est au bout
}
xn[NUMBER_OF_COEFS-1] = x;
//multiplier par les coef
for (i = 0; i < NUMBER_OF_COEFS; i++)
{
temp += xn[NUMBER_OF_COEFS - i] * coefs[i];
}
xy[0] = (int)(temp+0.5);
for (i = 0; i < NUMBER_OF_COEFS - 1; i++)
{
ynn[i] = ynn[i + 1];
}
ynn[NUMBER_OF_COEFS-1] = y;
temp = 0;
for (i = 0; i < NUMBER_OF_COEFS; i++)
{
temp += ynn[NUMBER_OF_COEFS - i] * coefs[i];
}
xy[1] = (int)(temp + 0.5);
return xy;
}
A couple of recommendations:
printf() can occasionally lag in its output. To be very sure that nothing is being printed, call fflush(stdout) after the print line. This will flush the stdout buffer-- if nothing is printed after the flush, then the println() really is not being executed.
How is your program terminating? If execution does not continue past the pwm_init() function, that almost certainly means that something bad is happening with the memory locations you are writing to. Double check that your register values are correct and that your program isn't being killed due to invalid memory access.
I am using Atmel Studio 6.1 and this is the code that I use, beside this i also got another code called "ledstrip.h". Which basically is an 1 dimensional array.
This is something for my study.
I am trying to send 12 bytes through a 'ledstrip'
code:
#define SPI_SS_bm PIN4_bm
#define SPI_MOSI_bm PIN5_bm
#define SPI_MISO_bm PIN6_bm
#define SPI_SCK_bm PIN7_bm
#define MIN_VALUE 0.4
#define F_CPU 32000000UL
#define P 128
#define FOO 0
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "ledstrip.h"
void spi_init(void);
uint8_t spi_transfer(uint8_t data);
const uint8_t *ptr = image;
uint8_t num[12];
int line;
int g;
int data;
int i;
void row (const uint8_t *j)
{
uint32_t row2 = 0;
for(g = 0; g < 4; g++)
{
for(int i = 0; i < 8; i++)
{
row2 = (row2 << 3) | pgm_read_byte(j);
j++;
}
num[3*g] = (uint8_t) (row2 >> 16); //put bytes in the right order
num[3*g+1] = (uint8_t) (row2 >> 8);
num[3*g+2] = (uint8_t) (row2);
}
}
void spi_initialisation(void)
{
PORTC.DIRSET = SPI_SCK_bm|SPI_MOSI_bm|SPI_SS_bm;
PORTC.DIRCLR = SPI_MISO_bm;
SPIC.CTRL = (!SPI_CLK2X_bm) | // no double clock speed
SPI_ENABLE_bm | // SPI enable
!SPI_DORD_bm | // data order, MSB first
SPI_MASTER_bm | // master
SPI_MODE_0_gc | // mode 0
SPI_PRESCALER_DIV4_gc; // Presc. 4 (#2 MHz,500kHz)
}
void spi_init(void)
{
PORTC.DIRSET = PIN7_bm|PIN5_bm|PIN4_bm; // 7: MOSI 5: SCK
PORTC.OUTCLR = PIN4_bm; // 4: latch enable
PORTD.DIRSET |= PIN3_bm|PIN1_bm; // 3: MOSI 1: SCK
USARTC1.BAUDCTRLA = 0; // baud rate FCPU/2
USARTC1.BAUDCTRLB = 0; //
USARTC1.CTRLC = USART_CMODE_MSPI_gc; // SPI mode
USARTC1.CTRLA = 0; // no interrupts
USARTC1.CTRLB = USART_TXEN_bm; // enable transmit
USARTD0.BAUDCTRLA = 0; // baud rate FCPU/2
USARTD0.BAUDCTRLB = 0; //
USARTD0.CTRLC = USART_CMODE_MSPI_gc; // SPI mode
USARTD0.CTRLA = 0; // no interrupts
USARTD0.CTRLB = USART_TXEN_bm; // enable transmit
}
void init_timer_phi(void)
{
TCE0.CTRLA = TC_CLKSEL_DIV8_gc; // prescaling P
TCE0.CTRLB = TC_WGMODE_NORMAL_gc; // normal mode
TCE0.INTCTRLA = TC_OVFINTLVL_LO_gc;
TCE0.PER = 1440; // t = PER*FCPU/P =
// FCPU*P/32M = 1 us
}
ISR (TCE0_OVF_vect)
{
ptr = ptr +32;
if(ptr >= image + 32 * 360)
{
ptr = image;
} // send bytes to ledstrip
}
void init_inputcapture(void)
{
PORTC.PIN2CTRL = PORT_ISC_FALLING_gc;
PORTC.DIRCLR = PIN2_bm; // Pin 2 is input
EVSYS.CH0MUX = EVSYS_CHMUX_PORTC_PIN2_gc; // Select PC2 as input
// to event channel 0
TCC0.CTRLD = TC_EVACT_CAPT_gc | // Event capture
TC_EVSEL_CH0_gc; // for Channel 0
TCC0.CTRLB = TC0_CCAEN_bm; // Enable Inp. Capt. Ch. A
TCC0.CTRLA = TC_CLKSEL_DIV256_gc; // Start timer
TCC0.INTCTRLB = TC_CCAINTLVL_LO_gc; // Set Interr. level Ch. A
TCC0.PER = 0xFFFF;
}
ISR(TCC0_CCA_vect)
{
uint16_t v;
v = TCC0.CCA;
if (v > MIN_VALUE)
{ // skip if measured value is too small
line = 0; // reset image
TCE0.PER = (v * 360/(F_CPU / P)); // calculate periode
TCC0.CTRLFSET = TC_CMD_RESTART_gc; // restart input capture
}
}
void spi_write_byte(uint8_t data)
{
PORTC.OUTCLR = SPI_SS_bm;
spi_transfer(data);
PORTC.OUTSET = SPI_SS_bm;
}
uint8_t spi_read_byte(void)
{
uint8_t data;
PORTC.OUTCLR = SPI_SS_bm;
data = spi_transfer (FOO);
PORTC.OUTSET = SPI_SS_bm;
return data;
}
int main(void)
{
uint8_t i = 0;
spi_init();
PORTC.DIRSET = PIN0_bm;
PMIC.CTRL |= PMIC_LOLVLEN_bm;
sei();
PORTC.DIRSET = PIN4_bm | PIN5_bm | PIN6_bm | PIN7_bm;
while(1)
{
SPIC.DATA = i; // send i
while( ! (SPIC.STATUS & (SPI_IF_bm)) ); // wait until send
PORTC.OUTSET = PIN0_bm; // store
PORTC.OUTCLR = PIN0_bm;
_delay_ms(100);
i++;
}
}
Okay, so I got this code with no errors and warnings.
But when I run the program on my microcontroller ATXMega128A4U, I don't get the intended output.
There is a possibility that I didn't connect the pins of my 'ledstrip' in the right way with the pins of the microcontroller.
But if we consider that I did it like I intended to, the problem should be in the code.
The intended signal is 12 bytes long and with that I can turn RGB LED's on or off.
The RGB LED's are put together in a so called 'ledstrip'
Now what I'm getting is that some of the RGB LED's turn on and are Red Green or Blue.
What i should be getting is something like a chasing RGB LED row.
So you would see the LED's turn on or off at a certain frequency.
I am trying to get a pic16 controller to run an initialization function that displays some text on an LCD only once and then goes on to display other things
The LCD output is working fine the problem is that the initialization function keeps executing. What am I doing wrong ?
/*
* File: main.c
*
* Created on Sep 1, 2013, 12:09 PM
*/
#include <pic.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "delay.h"
__CONFIG(WDTE_ON & PWRTE_ON & MCLRE_ON & BOREN_ON & FOSC_INTRCIO );
static int exec_counter = 0;
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) // bit mask macros
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define flip_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define test_bit(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define E RC4 // Define the LCD Control Pins
#define RS RC5
int i; // Use Global Variables for Debug
LCDWrite(int LCDData, int RSValue)
{
PORTC = (LCDData >> 4) & 0x0F; // Get High 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the High 4 Bits Out
PORTC = LCDData & 0x0F; // Get Low 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the Low 4 Bits Out
if ((0 == (LCDData & 0xFC)) && (0 == RSValue))
DelayMs(5);
else
DelayUs(200);
} //
void writeLines(char top[],char bottom[]){
for (i = 0; top[i] != 0; i++) // Write Line 1
LCDWrite(top[i], 1);
LCDWrite(0b11000000, 0); // Move Cursor to the Second Line
for (i = 0; bottom[i] != 0; i++)// Write Line 2
LCDWrite(bottom[i], 1);
}
int countelems(char arr[]){
for (i = 0; arr[i] != 0; i++){}
return i;
}
void pad_number(char number[],char numberout[],char unit[]){
int size_n = countelems(number); // get length of number array by reference
int size_u = countelems(unit); // get length of unit array by reference
int size = size_u + size_n + 1; // calculate total size of text with 1 space between number and unit
int L_space = floor((16-size)/2)-1; // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
numberout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= (size_n); i++){
numberout[i+(L_space+1)] = number[i]; // fill output char array with number
}
numberout[L_space+size_n+1] = 0b10100000; // put space in output char array between number and unit
for (i = 0; i <= size_u; i++){
numberout[i+(L_space+size_n+2)] = unit[i]; // fill output char array with unit
}
}
void pad_text(char text[],char textout[]){
int size = countelems(text); // get length of char array by reference
int L_space = floor((16-size)/2); // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
textout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= 15; i++){
if( i >= L_space && i <= (L_space+size)){
textout[i] = text[i-L_space]; // fill middle of output char array with text
}
}
}
void getAnalog(int channel,char parameter[], char unit[]){
char output_parameter[16];
char output_number[16];
char number[16];
ADCON0 = channel << 2; // select channel
//set_bit(ADCON0,7); // set ADFM flag so LSB is bit 0 of ADRESL
set_bit(ADCON0,0); // switch ADC on = set ADON flag 0b00000001
sampleTime(); // wait required aquisition time
set_bit(ADCON0,1); // start conversion = set GO/DONE bit
while(test_bit(ADCON0,1)){/* wait for ADC to complete conversion */;}
int ADCresult = (ADRESL+ADRESH)/10; // get result from ADC
itoa(number,ADCresult,10); // convert ADC result to charstring
LCDWrite(0b00000001, 0); // Clear LCD
pad_text(parameter,output_parameter);
pad_number(number,output_number,unit);
writeLines(output_parameter, output_number);
}
void init(){
DelayMs(20); // Wait for LCD to Power Up
PORTC = 3; // Start Initialization Process
E = 1; E = 0; // Send Reset Command
DelayMs(5);
E = 1; E = 0; // Repeat Reset Command
DelayUs(200);
E = 1; E = 0; // Repeat Reset Command Third Time
DelayUs(200);
PORTC = 2; // Initialize LCD 4 Bit Mode
E = 1; E = 0;
DelayUs(200);
LCDWrite(0b00101000, 0); // LCD is 4 Bit I/F, 2 Line
LCDWrite(0b00000001, 0); // Clear LCD
LCDWrite(0b00000110, 0); // Move Cursor After Each Character
LCDWrite(0b00001110, 0); // Turn On LCD and Enable Cursor
// "0123456789012345"
writeLines( " INITIALIZE ",
" TEXT ");
}
void main(void) {
OPTION_REG |= 0x7; // set prescaler to 1:128 or 2.3 Seconds
OPTION_REG |= 0x8; // assign prescaler to WDT
TRISA = 0b00000101; // configure PORTA set RA0 and RA2 to analog input;
ANSEL = 0b00000101; // disable input buffers if I/O pins RA0 and RA2
TRISC = 0; // configure PORTC as output
ADCON1 = 0; // select FOSC2
if (exec_counter == 0){
exec_counter++;
init();
DelayS(4);
}
PORTC = 0;
while (1) {
getAnalog(0,"VELOCITY","KM/H");
DelayS(4);
getAnalog(2,"ACCELERATION","M/S^2");
DelayS(4);
}
return;
}
/*
* File: delay.c
*
* Created on Sep 3, 2013, 12:09 PM
*/
#include "delay.h"
#include <pic.h>
#define _XTAL_FREQ 4000000
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char i;
do {
i = 4;
do {
DelayUs(250);
} while(--i);
} while(--cnt);
#endif
}
void DelayS(unsigned int count){
for (int i=0; i<=count;i++){
NOP();
CLRWDT();
DelayMs(1000);
}
}
void sampleTime(){
// TC = – 10pF ( 1k Ω + 7k Ω + 1k Ω ) ln(0.0004885)
// = 0.686 μS
// TACQ = 5μS + 0.686μS + [ ( 50°C- 25°C ) ( 0.05μ S /°C ) ]
// = 6.936 μS /
// 1 instruction cycle = 4μS # 1 mHz
// 1 instruction cycle = 1μS # 4 mHz
// 1 instruction cycle = 500nS # 8 mHz
// 1 instruction cycle = 200nS # 20 mHz
// TACQ # 1 mHz is 6.936 μS / 4 μS or ~ 2 instruction cycles
// TACQ # 4 mHz is 6.936 μS / 1 μS or ~ 7 instruction cycles
// TACQ # 8 mHz is 6.936 μS / 0.5 μS or ~ 14 instruction cycles
// TACQ # 20 mHz is 6.936 μS / 0.2 μS or ~ 35 instruction cycles
DelayUs(8);
}
The char number[] = ""; array is very small, yet you use it in itoa(), thus overwriting random memory.
I'm using C to write a program on an 8051 microcontroller. The compiler I'm using is Keil Microvision. I'm stuck and having trouble figuring out what is missing from my code. I know it's very basic code I just can't figure out what I'm supposed to do.
So pretty much what I am doing is taking sending a sentence out to the user and having them answer yes or no through the serial port and I used a serial interrupt. That part works fine. If I get a no from the person I want to generate a square wave 5kHz by a timer interrupt. I want this square wave to be controlled by an external interrupt turning it on and off when the external interrupt on pin P3.2 is either on or off.
Here is all my code
#include <REG52.H>
#include <stdio.h>
sbit WAVE = P1 ^ 7;
#define BIT(x) (1 << (x))
void timer0() interrupt 1 // timer is controlling square wave timer 0
{
WAVE = ~WAVE;
}
void interrupt0() interrupt 0
{
IE ^= BIT(1);
}
void serial0() interrupt 4
{
unsigned char x;
unsigned int i, z;
unsigned char yes[] = " YES ";
unsigned char no[] = " NO ";
unsigned char nvalid[] = " NOT VALID TRY AGAIN ";
while (RI == 1) {
x = SBUF;
RI = 0;
if (z < 1) {
if (x == 'n') {
for (i = 0; i < 4; i++) {
SBUF = no[i];
while (TI == 0) ; //wait for transmit
TI = 0;
z++;
}
}
} else {
return;
}
if (x == 'y') {
for (i = 0; i < 5; i++) {
SBUF = yes[i];
while (TI == 0) ;
TI = 0;
}
} else if (x != 'n') {
for (i = 0; i < 21; i++) {
SBUF = nvalid[i];
while (TI == 0) ;
TI = 0;
}
}
TI = 0;
return;
}
}
void main()
{
TMOD = 0x20;
TH1 = 0xF6; //baud rate
SCON = 0x50;
TH0 = 0xA4;
IE = 0x93; //enable interrupts
IP = 0x10; // propriety to serial interrupt
TR1 = 1; //start timer 1
TR0 = 1; //clear timer 0
TI = 1;
printf("Hello, Are you okay? Press y for yes and n for no ");
while (1) ;
}
The part I'm having trouble with is these two interrupt from the previous code
void timer0() interrupt 1 // timer is controlling square wave timer 0
{
WAVE=~WAVE;
}
void interrupt0() interrupt 0
{
IE ^= BIT(1);
}
Any hints in the right direction would be greatly appreciated! Thanks. Sorry about formatting
Variables that are modified by interrupts should be defined as volatile:
volatile sbit WAVE = P1 ^ 7;