Pages: [1]   Go Down
Author Topic: PROGMEM char array  (Read 2535 times)
0 Members and 1 Guest are viewing this topic.
Bologna
Offline Offline
Newbie
*
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

consider this snippet, compiled with Arduino IDE:

Code:
PROGMEM  char charSet[]  = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
char reversed[]  = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
char ff;
for (int i=0; i < 16; i++) {
Serial.print(" ");
Serial.print(reversed[i], HEX);
}
Serial.println(" ");
for (int i=0; i < 16; i++) {
Serial.print(" ");
ff = pgm_read_byte(&charSet[i]);
Serial.print(ff);
}


I would expect the two for loops to produce same output. But the output is:
Code:
     0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F
      FFFFFF94 FFFFFFB0 6 FFFFFF80 FFFFFF91 FFFFFFC7 3 62 FFFFFFE3 E FFFFFF94 5E 29 FFFFFF99 23 39


What am I missing? Thank you

Logged

twitter: @shineangelic

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 76
Posts: 2247
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

try a different declaration
Code:
char charSet[]  PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };

also try below instead of assigning to ff

Code:
Serial.print( pgm_read_byte( charSet + i ) );
Logged


0
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12725
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The AVR microcontrollers are Harvard architecture - code and data are in separate memories (flash and SRAM respectively).
Logged

[ I won't respond to messages, use the forum please ]

Leeds, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Surely you want Serial.print(ff, HEX); rather than just Serial.print(ff);
 if you want the output to look the same.

Having said that, it looks like serial.print is assuming you have passed a long rather than a char, which I don't understand yet.

Paul
Logged

Bologna
Offline Offline
Newbie
*
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Surely you want Serial.print(ff, HEX); rather than just Serial.print(ff);
 if you want the output to look the same.

Yes, you're right. Anyway the output is the same. Also

Code:
Serial.print( pgm_read_byte( charSet + i ), HEX );

produces same output. I really can't understand
Logged

twitter: @shineangelic

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Having said that, it looks like serial.print is assuming you have passed a long rather than a char, which I don't understand yet.

All of the various print(type, base) overloads are piping through print(long, base) apparently to avoid code duplication.  The unfortunate side effect is that Hex values print with too many leading Fs.
Logged


Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26632
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The unfortunate side effect is that Hex values print with too many leading Fs.
Only if you're using signed datatypes.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Leeds, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So ff should be an unsigned char  as in?

Code:
unsigned char ff;

Paul
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26632
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Or "byte", as in " pgm_read_byte"
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Bologna
Offline Offline
Newbie
*
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'v tried with unsigned char and byte, but no luck. The output is:

Code:
0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F
 91 C8 3 A8 16 B9 6 CA 6 DB 6 A1 F0 E 94 D3

The code I'm using is:

Code:
byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
byte reversed[]  = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
byte ff;
for (int i=0; i < 16; i++) {
Serial.print(" ");
Serial.print(reversed[i], HEX);
}
Serial.println(" ");
for (int i=0; i < 16; i++) {
Serial.print(" ");
ff = pgm_read_byte(&charSet[i]);
Serial.print(ff, HEX);
}
Logged

twitter: @shineangelic

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:



const byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
byte reversed[]  = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };

void setup() {
    Serial.begin(115200);

byte ff;
for (int i=0; i < 16; i++) {
Serial.print(" ");
Serial.print(reversed[i], HEX);
}
Serial.println(" ");
for (int i=0; i < 16; i++) {
Serial.print(" ");
ff = pgm_read_byte(&charSet[i]);
Serial.print(ff, HEX);
}
}

void loop() {

}

returns
Code:
0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F
 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F
on my computer/arduino.

Code:
$ avr-gcc -v
Using built-in specs.
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/avr/4.7.1/lto-wrapper
Target: avr
Configured with: /build/src/gcc-4.7.1/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,c++ --disable-libssp --disable-nls --target=avr --with-as=/usr/bin/avr-as --with-ld=/usr/bin/avr-ld --with-gnu-as --with-gnu-ld
Thread model: single
gcc version 4.7.1 (GCC)

$ pacman -Qi avr-libc
Name           : avr-libc
Version        : 1.8.0-4
URL            : http://savannah.nongnu.org/projects/avr-libc/
Licenses       : BSD
Groups         : None
Provides       : None
Depends On     : avr-gcc
Optional Deps  : None
Required By    : None
Conflicts With : None
Replaces       : None
Installed Size : 23684.00 KiB
Packager       : schuay <jakob.gruber@gmail.com>
Architecture   : any
Build Date     : Sun Jun 24 01:12:18 2012
Install Date   : Thu Jun 28 08:33:48 2012
Install Reason : Explicitly installed
Install Script : No
Description    : The C runtime library for the AVR family of microcontrollers


arduino uno r2
Logged

Bologna
Offline Offline
Newbie
*
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you. I had to add const keyword and to move the declaration outside the function.

Now it works.
Logged

twitter: @shineangelic

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26632
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's why we prefer it that you DON'T post code snippets
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Bologna
Offline Offline
Newbie
*
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The snippet is part of a rudimental Air conditioner IR driver, I thought it was too long to be posted for a simple issue.

I'll post it, so maybe someone will find other inconsistencies in my rusty C code. It works, but I'd like to decrease memory usage furthermore.

Thanks to anyone who'll be looking at it.


Code:
#include <avr/pgmspace.h>
//These are Samsung MH026FB specific
#define tempmask 0xF//temp e` quarto byte dell'input
#define funmask 0xF0
#define fanmask 0x700
#define swirlmask 0x800

#include "IRremoteInt_light.h"
#include "IRremote_light.h"

const byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };

#define DEBUG 1
/**
 Souliss Aircon MH026FB Driver
 implements IR logic. Commanded by Souliss AirCon protocol
 
 SAMSUNG MH026 series
 
*/
//IR_Remote lite library
IRsend irsend;
/**
Counts number of 1 in a long
*/
int NumberOfSetBits(long i)
{
    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
/**
 Reverse the bit in a byte via a lookup table
 Bit reversal lookup table
 0100 --> 0010
 //TODO use progmem
*/
char revbits(int n)
{

return pgm_read_byte(&charSet[n]);
//return reversed[n];
}
/**
Compute Samsung crappy checksum
Command is split between data and data2

Samsung checksum
1. Count the number of 1 bits in all the bytes except #2 (checksum)
2. Compute count mod 15. If the value is 0, use 15 instead.
3. Take the value from 2, flip the 4 bits, and reverse the 4 bits.
4. The checksum is Bn where n is the value from the previous step.

Note that step 2 is mod 15, not mod 16 (which you might expect). I
don't know why 15 is used as a special case instead of 0.

For step 3, the results in order are F, 7, B, 3, D, 5, 9, 1, E, 6, A,
2, C, 4, 8, 0. Note that these are exactly the same as the values you
got for byte 5 (temperature). This suggests that the reversed /
inverted bits are more "fundamental".

Thanks to Ken Shirriff
*/
long computeChecksum(long data, long data2){
char temp;
temp = NumberOfSetBits(data2);
temp +=NumberOfSetBits(data);
temp = temp%15;
if (temp == 0)
temp = 15;
#ifdef DEBUG
Serial.print("NUMBITS SET:");
Serial.println(temp, HEX);
#endif
temp = ~temp;
temp -=0xF0;
#ifdef DEBUG
Serial.print("INVERTED:");
Serial.println(temp, HEX);
Serial.print("REVERSED:");
Serial.println(revbits(temp), HEX);
#endif

return 0xB0 + revbits(temp);
}

/**************************************************************************
/*!
Remap Souliss AirCon data with device specific one (Samsung MH026FB).
You'll have to re-implement this function to support your
Air Conditioner. Souliss INPUT Data is:

0xABCD
A = 4 bit mask (XYZT X= powerON, Y PowerOFF, ionizer (airclean) , pwrsave)
B = Fan/Swirl (1bit switch + 3bits for four possible fan values)
C = Function (auto,cool,dry,fan,heat)
D = Temperature (from 16 to 30, see .h)

I comandi sono formati da due o tre burst


  ---------------------------------------------------------------
OUTPUT (Samsung specific)
Codice dati da inviare: 7F       XX       80       71       F    1    7    7    F0
const    check    swirl    const    ion  tem  fan  fun  const
DEFAULT 00000000 00000000 00000000 01110001 0000 0000 0000 0000 00000000

*/
/**************************************************************************/
void sendMH026FB(unsigned long data, U8 *memory_map, U8 slot){

long part1=0;
long part2=0;

#ifdef DEBUG
Serial.print("Souliss AirCon input:");
Serial.println(data, HEX);
#endif

if (data & 0x8000){//if first bit of input=0 TURN ON
#ifdef DEBUG
Serial.println("POWERON!");
#endif
irsend.sendSamsung(0xBFB20FFF, 0xFFFFF0);
irsend.sendSamsung(0x7FB40FFF, 0xFFFFFF);
//*status = Souliss_T_IrCom_AirCon_Pow_On;
//go on with command
}
else if (data<<1 & 0x8000) {//if second bit of input=0 SHUT OFF
#ifdef DEBUG
Serial.println("POWEROFF!");
#endif
irsend.sendSamsung(0xBFB20FFF, 0xFFFFFC);
irsend.sendSamsung(0x7FB40FFF, 0xFFFFFF);
irsend.sendSamsung(0x7FB08A71, 0xF84FFC);
//*status = Souliss_T_IrCom_AirCon_Pow_Off;

//memory_map[MaCaco_OUT_s + slot] = *status;
//memory_map[MaCaco_OUT_s + slot + 1] = *status;
memory_map[MaCaco_IN_s + slot] = Souliss_T_IrCom_AirCon_Reset;
return;
}
else {//Comando da due bursts, primo costante
irsend.sendSamsung(0xBFB20FFFUL ,0xFFFFF0UL );
}
//starting values
part1 =  0x7f000000;
part2 =  0x0000F0;
//last part1 const (andrebbe 11 -> turbo) e 01->Powersave
unsigned int powerMode = Souliss_T_IrCom_AirCon_opt_normal;
//FAN is bit 2,3,4 of 2nd BYTE of INPUT
char fan = (data & fanmask)>>8;
//FUN = 3rd byte of INPUT
char fun = (data & funmask)>>4;

//TEMP = 4th byte of INPUT
long temperat = data & tempmask;
//swirl OFF by default
unsigned int swirl = 0x80;

//swirl (if deflector has to swing)
if (data & swirlmask){
swirl=0x8A;
}

//Eco bit Toggle, only in cool mode
if ((data<<3 & 0x8000) && (fun == Souliss_T_IrCom_AirCon_Fun_Cool))
powerMode = Souliss_T_IrCom_AirCon_opt_eco;

//PART2

//OPT if terzo bit = 1 IONIZER
if (data<<2 & 0x8000)
part2 += 0x700000;//Ion ON
else
part2 += 0xF00000;//F = Ion OFF


//Fan has only 24 degrees
if (fun == Souliss_T_IrCom_AirCon_Fun_Fan)
temperat = Souliss_T_IrCom_AirCon_temp_24C;

//Dry has only AUTO fan setting
if (fun == Souliss_T_IrCom_AirCon_Fun_Dry)
fan = Souliss_T_IrCom_AirCon_Fan_Auto;

//Auto mode adjust: fan and options are fixed
if (fun == Souliss_T_IrCom_AirCon_Fun_Auto){
fan = 0x4;
//swirl=0x8A;
powerMode = Souliss_T_IrCom_AirCon_opt_normal;
}

part1 += swirl<<8;
part1 += powerMode;
//temperature on sixth byte
part2 += temperat<<16;

part2 += fan<<12;
part2 += fun<<8;

//has to be last call
part1 += computeChecksum(part1, part2)<<16;

//send command
irsend.sendSamsung(part1, part2);
#ifdef DEBUG
Serial.print("Sending 0x");
Serial.print(part1, HEX);
Serial.print(" ");
Serial.println(part2, HEX);
#endif

//*status = data;
}
Logged

twitter: @shineangelic

Pages: [1]   Go Up
Jump to: