EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: georgian on November 09, 2020, 09:52:11 pm

Title: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 09, 2020, 09:52:11 pm
Hello guys,

I'm working on some sort of 8bit to 12bit encoder/decoder (not sure how to name it). I want to have an 8bit BCD input displayed on 3 7-segment displays. For this I want to use an D27C210 EPROM (because it has more than enough outputs).

Using the code below i split a number into its digits and than concatenate them to get the desired combination.
for example: address 1 -> 0x1.....address 100 -> 0x100...address 255 -> 0x255.

The questions are, how to arrange the data into one file, or table. Can i just use fopen() to create a file and write to it? What should i write? HEX or DEC value? The output file should be compatible with the TL866II Plus programmer (I don't have it yet, but it's on the way)

I know that there are other ways to achieve this but I still want to know how to generate a HEX file for an EPROM.

Thanks a lot.

Code: [Select]
#include<stdlib.h>
#include<stdio.h>

int finalResult();
int split(int length);

int digits[3]; //Array to store each digit.

int main() {
//Test routine
for (int i = 0; i < 256; i++) {
split(i);
printf("Address: %d\tValue HEX: 0x%X  \tValue DEC: %d\n", i, finalResult(), finalResult());
}
return 0;
}

//Split the number into 3 digits and store them in an array.
int split(int input) {
int pos = 0;
while (input > 0) {
  int digit = input % 10;
  digits[pos] = digit; pos++;
  input /= 10;
  }
return pos;
}
//Concatenate the digits each ito it's right position.
int finalResult() {
int res = ((digits[2] << 8) | digits[1] << 4) | digits[0];
return res;
}

Console output:
Code: [Select]
Address: 0	Value HEX: 0x0  	Value DEC: 0
Address: 1 Value HEX: 0x1  Value DEC: 1
Address: 2 Value HEX: 0x2  Value DEC: 2
Address: 3 Value HEX: 0x3  Value DEC: 3
Address: 4 Value HEX: 0x4  Value DEC: 4
Address: 5 Value HEX: 0x5  Value DEC: 5
Address: 6 Value HEX: 0x6  Value DEC: 6
Address: 7 Value HEX: 0x7  Value DEC: 7
Address: 8 Value HEX: 0x8  Value DEC: 8
Address: 9 Value HEX: 0x9  Value DEC: 9
Address: 10 Value HEX: 0x10  Value DEC: 16
Address: 11 Value HEX: 0x11  Value DEC: 17
Address: 12 Value HEX: 0x12  Value DEC: 18
Address: 13 Value HEX: 0x13  Value DEC: 19
Address: 14 Value HEX: 0x14  Value DEC: 20
Address: 15 Value HEX: 0x15  Value DEC: 21
Address: 16 Value HEX: 0x16  Value DEC: 22
Address: 17 Value HEX: 0x17  Value DEC: 23
Address: 18 Value HEX: 0x18  Value DEC: 24
Address: 19 Value HEX: 0x19  Value DEC: 25
Address: 20 Value HEX: 0x20  Value DEC: 32
Address: 21 Value HEX: 0x21  Value DEC: 33
Address: 22 Value HEX: 0x22  Value DEC: 34
Address: 23 Value HEX: 0x23  Value DEC: 35
Address: 24 Value HEX: 0x24  Value DEC: 36
Address: 25 Value HEX: 0x25  Value DEC: 37
Address: 26 Value HEX: 0x26  Value DEC: 38
Address: 27 Value HEX: 0x27  Value DEC: 39
Address: 28 Value HEX: 0x28  Value DEC: 40
Address: 29 Value HEX: 0x29  Value DEC: 41
Address: 30 Value HEX: 0x30  Value DEC: 48
Address: 31 Value HEX: 0x31  Value DEC: 49
Address: 32 Value HEX: 0x32  Value DEC: 50
Address: 33 Value HEX: 0x33  Value DEC: 51
Address: 34 Value HEX: 0x34  Value DEC: 52
Address: 35 Value HEX: 0x35  Value DEC: 53
Address: 36 Value HEX: 0x36  Value DEC: 54
Address: 37 Value HEX: 0x37  Value DEC: 55
Address: 38 Value HEX: 0x38  Value DEC: 56
Address: 39 Value HEX: 0x39  Value DEC: 57
Address: 40 Value HEX: 0x40  Value DEC: 64
Address: 41 Value HEX: 0x41  Value DEC: 65
Address: 42 Value HEX: 0x42  Value DEC: 66
Address: 43 Value HEX: 0x43  Value DEC: 67
Address: 44 Value HEX: 0x44  Value DEC: 68
Address: 45 Value HEX: 0x45  Value DEC: 69
Address: 46 Value HEX: 0x46  Value DEC: 70
Address: 47 Value HEX: 0x47  Value DEC: 71
Address: 48 Value HEX: 0x48  Value DEC: 72
Address: 49 Value HEX: 0x49  Value DEC: 73
Address: 50 Value HEX: 0x50  Value DEC: 80
Address: 51 Value HEX: 0x51  Value DEC: 81
Address: 52 Value HEX: 0x52  Value DEC: 82
Address: 53 Value HEX: 0x53  Value DEC: 83
Address: 54 Value HEX: 0x54  Value DEC: 84
Address: 55 Value HEX: 0x55  Value DEC: 85
Address: 56 Value HEX: 0x56  Value DEC: 86
Address: 57 Value HEX: 0x57  Value DEC: 87
Address: 58 Value HEX: 0x58  Value DEC: 88
Address: 59 Value HEX: 0x59  Value DEC: 89
Address: 60 Value HEX: 0x60  Value DEC: 96
Address: 61 Value HEX: 0x61  Value DEC: 97
Address: 62 Value HEX: 0x62  Value DEC: 98
Address: 63 Value HEX: 0x63  Value DEC: 99
Address: 64 Value HEX: 0x64  Value DEC: 100
Address: 65 Value HEX: 0x65  Value DEC: 101
Address: 66 Value HEX: 0x66  Value DEC: 102
Address: 67 Value HEX: 0x67  Value DEC: 103
Address: 68 Value HEX: 0x68  Value DEC: 104
Address: 69 Value HEX: 0x69  Value DEC: 105
Address: 70 Value HEX: 0x70  Value DEC: 112
Address: 71 Value HEX: 0x71  Value DEC: 113
Address: 72 Value HEX: 0x72  Value DEC: 114
Address: 73 Value HEX: 0x73  Value DEC: 115
Address: 74 Value HEX: 0x74  Value DEC: 116
Address: 75 Value HEX: 0x75  Value DEC: 117
Address: 76 Value HEX: 0x76  Value DEC: 118
Address: 77 Value HEX: 0x77  Value DEC: 119
Address: 78 Value HEX: 0x78  Value DEC: 120
Address: 79 Value HEX: 0x79  Value DEC: 121
Address: 80 Value HEX: 0x80  Value DEC: 128
Address: 81 Value HEX: 0x81  Value DEC: 129
Address: 82 Value HEX: 0x82  Value DEC: 130
Address: 83 Value HEX: 0x83  Value DEC: 131
Address: 84 Value HEX: 0x84  Value DEC: 132
Address: 85 Value HEX: 0x85  Value DEC: 133
Address: 86 Value HEX: 0x86  Value DEC: 134
Address: 87 Value HEX: 0x87  Value DEC: 135
Address: 88 Value HEX: 0x88  Value DEC: 136
Address: 89 Value HEX: 0x89  Value DEC: 137
Address: 90 Value HEX: 0x90  Value DEC: 144
Address: 91 Value HEX: 0x91  Value DEC: 145
Address: 92 Value HEX: 0x92  Value DEC: 146
Address: 93 Value HEX: 0x93  Value DEC: 147
Address: 94 Value HEX: 0x94  Value DEC: 148
Address: 95 Value HEX: 0x95  Value DEC: 149
Address: 96 Value HEX: 0x96  Value DEC: 150
Address: 97 Value HEX: 0x97  Value DEC: 151
Address: 98 Value HEX: 0x98  Value DEC: 152
Address: 99 Value HEX: 0x99  Value DEC: 153
Address: 100 Value HEX: 0x100  Value DEC: 256
Address: 101 Value HEX: 0x101  Value DEC: 257
Address: 102 Value HEX: 0x102  Value DEC: 258
Address: 103 Value HEX: 0x103  Value DEC: 259
Address: 104 Value HEX: 0x104  Value DEC: 260
Address: 105 Value HEX: 0x105  Value DEC: 261
Address: 106 Value HEX: 0x106  Value DEC: 262
Address: 107 Value HEX: 0x107  Value DEC: 263
Address: 108 Value HEX: 0x108  Value DEC: 264
Address: 109 Value HEX: 0x109  Value DEC: 265
Address: 110 Value HEX: 0x110  Value DEC: 272
Address: 111 Value HEX: 0x111  Value DEC: 273
Address: 112 Value HEX: 0x112  Value DEC: 274
Address: 113 Value HEX: 0x113  Value DEC: 275
Address: 114 Value HEX: 0x114  Value DEC: 276
Address: 115 Value HEX: 0x115  Value DEC: 277
Address: 116 Value HEX: 0x116  Value DEC: 278
Address: 117 Value HEX: 0x117  Value DEC: 279
Address: 118 Value HEX: 0x118  Value DEC: 280
Address: 119 Value HEX: 0x119  Value DEC: 281
Address: 120 Value HEX: 0x120  Value DEC: 288
Address: 121 Value HEX: 0x121  Value DEC: 289
Address: 122 Value HEX: 0x122  Value DEC: 290
Address: 123 Value HEX: 0x123  Value DEC: 291
Address: 124 Value HEX: 0x124  Value DEC: 292
Address: 125 Value HEX: 0x125  Value DEC: 293
Address: 126 Value HEX: 0x126  Value DEC: 294
Address: 127 Value HEX: 0x127  Value DEC: 295
Address: 128 Value HEX: 0x128  Value DEC: 296
Address: 129 Value HEX: 0x129  Value DEC: 297
Address: 130 Value HEX: 0x130  Value DEC: 304
Address: 131 Value HEX: 0x131  Value DEC: 305
Address: 132 Value HEX: 0x132  Value DEC: 306
Address: 133 Value HEX: 0x133  Value DEC: 307
Address: 134 Value HEX: 0x134  Value DEC: 308
Address: 135 Value HEX: 0x135  Value DEC: 309
Address: 136 Value HEX: 0x136  Value DEC: 310
Address: 137 Value HEX: 0x137  Value DEC: 311
Address: 138 Value HEX: 0x138  Value DEC: 312
Address: 139 Value HEX: 0x139  Value DEC: 313
Address: 140 Value HEX: 0x140  Value DEC: 320
Address: 141 Value HEX: 0x141  Value DEC: 321
Address: 142 Value HEX: 0x142  Value DEC: 322
Address: 143 Value HEX: 0x143  Value DEC: 323
Address: 144 Value HEX: 0x144  Value DEC: 324
Address: 145 Value HEX: 0x145  Value DEC: 325
Address: 146 Value HEX: 0x146  Value DEC: 326
Address: 147 Value HEX: 0x147  Value DEC: 327
Address: 148 Value HEX: 0x148  Value DEC: 328
Address: 149 Value HEX: 0x149  Value DEC: 329
Address: 150 Value HEX: 0x150  Value DEC: 336
Address: 151 Value HEX: 0x151  Value DEC: 337
Address: 152 Value HEX: 0x152  Value DEC: 338
Address: 153 Value HEX: 0x153  Value DEC: 339
Address: 154 Value HEX: 0x154  Value DEC: 340
Address: 155 Value HEX: 0x155  Value DEC: 341
Address: 156 Value HEX: 0x156  Value DEC: 342
Address: 157 Value HEX: 0x157  Value DEC: 343
Address: 158 Value HEX: 0x158  Value DEC: 344
Address: 159 Value HEX: 0x159  Value DEC: 345
Address: 160 Value HEX: 0x160  Value DEC: 352
Address: 161 Value HEX: 0x161  Value DEC: 353
Address: 162 Value HEX: 0x162  Value DEC: 354
Address: 163 Value HEX: 0x163  Value DEC: 355
Address: 164 Value HEX: 0x164  Value DEC: 356
Address: 165 Value HEX: 0x165  Value DEC: 357
Address: 166 Value HEX: 0x166  Value DEC: 358
Address: 167 Value HEX: 0x167  Value DEC: 359
Address: 168 Value HEX: 0x168  Value DEC: 360
Address: 169 Value HEX: 0x169  Value DEC: 361
Address: 170 Value HEX: 0x170  Value DEC: 368
Address: 171 Value HEX: 0x171  Value DEC: 369
Address: 172 Value HEX: 0x172  Value DEC: 370
Address: 173 Value HEX: 0x173  Value DEC: 371
Address: 174 Value HEX: 0x174  Value DEC: 372
Address: 175 Value HEX: 0x175  Value DEC: 373
Address: 176 Value HEX: 0x176  Value DEC: 374
Address: 177 Value HEX: 0x177  Value DEC: 375
Address: 178 Value HEX: 0x178  Value DEC: 376
Address: 179 Value HEX: 0x179  Value DEC: 377
Address: 180 Value HEX: 0x180  Value DEC: 384
Address: 181 Value HEX: 0x181  Value DEC: 385
Address: 182 Value HEX: 0x182  Value DEC: 386
Address: 183 Value HEX: 0x183  Value DEC: 387
Address: 184 Value HEX: 0x184  Value DEC: 388
Address: 185 Value HEX: 0x185  Value DEC: 389
Address: 186 Value HEX: 0x186  Value DEC: 390
Address: 187 Value HEX: 0x187  Value DEC: 391
Address: 188 Value HEX: 0x188  Value DEC: 392
Address: 189 Value HEX: 0x189  Value DEC: 393
Address: 190 Value HEX: 0x190  Value DEC: 400
Address: 191 Value HEX: 0x191  Value DEC: 401
Address: 192 Value HEX: 0x192  Value DEC: 402
Address: 193 Value HEX: 0x193  Value DEC: 403
Address: 194 Value HEX: 0x194  Value DEC: 404
Address: 195 Value HEX: 0x195  Value DEC: 405
Address: 196 Value HEX: 0x196  Value DEC: 406
Address: 197 Value HEX: 0x197  Value DEC: 407
Address: 198 Value HEX: 0x198  Value DEC: 408
Address: 199 Value HEX: 0x199  Value DEC: 409
Address: 200 Value HEX: 0x200  Value DEC: 512
Address: 201 Value HEX: 0x201  Value DEC: 513
Address: 202 Value HEX: 0x202  Value DEC: 514
Address: 203 Value HEX: 0x203  Value DEC: 515
Address: 204 Value HEX: 0x204  Value DEC: 516
Address: 205 Value HEX: 0x205  Value DEC: 517
Address: 206 Value HEX: 0x206  Value DEC: 518
Address: 207 Value HEX: 0x207  Value DEC: 519
Address: 208 Value HEX: 0x208  Value DEC: 520
Address: 209 Value HEX: 0x209  Value DEC: 521
Address: 210 Value HEX: 0x210  Value DEC: 528
Address: 211 Value HEX: 0x211  Value DEC: 529
Address: 212 Value HEX: 0x212  Value DEC: 530
Address: 213 Value HEX: 0x213  Value DEC: 531
Address: 214 Value HEX: 0x214  Value DEC: 532
Address: 215 Value HEX: 0x215  Value DEC: 533
Address: 216 Value HEX: 0x216  Value DEC: 534
Address: 217 Value HEX: 0x217  Value DEC: 535
Address: 218 Value HEX: 0x218  Value DEC: 536
Address: 219 Value HEX: 0x219  Value DEC: 537
Address: 220 Value HEX: 0x220  Value DEC: 544
Address: 221 Value HEX: 0x221  Value DEC: 545
Address: 222 Value HEX: 0x222  Value DEC: 546
Address: 223 Value HEX: 0x223  Value DEC: 547
Address: 224 Value HEX: 0x224  Value DEC: 548
Address: 225 Value HEX: 0x225  Value DEC: 549
Address: 226 Value HEX: 0x226  Value DEC: 550
Address: 227 Value HEX: 0x227  Value DEC: 551
Address: 228 Value HEX: 0x228  Value DEC: 552
Address: 229 Value HEX: 0x229  Value DEC: 553
Address: 230 Value HEX: 0x230  Value DEC: 560
Address: 231 Value HEX: 0x231  Value DEC: 561
Address: 232 Value HEX: 0x232  Value DEC: 562
Address: 233 Value HEX: 0x233  Value DEC: 563
Address: 234 Value HEX: 0x234  Value DEC: 564
Address: 235 Value HEX: 0x235  Value DEC: 565
Address: 236 Value HEX: 0x236  Value DEC: 566
Address: 237 Value HEX: 0x237  Value DEC: 567
Address: 238 Value HEX: 0x238  Value DEC: 568
Address: 239 Value HEX: 0x239  Value DEC: 569
Address: 240 Value HEX: 0x240  Value DEC: 576
Address: 241 Value HEX: 0x241  Value DEC: 577
Address: 242 Value HEX: 0x242  Value DEC: 578
Address: 243 Value HEX: 0x243  Value DEC: 579
Address: 244 Value HEX: 0x244  Value DEC: 580
Address: 245 Value HEX: 0x245  Value DEC: 581
Address: 246 Value HEX: 0x246  Value DEC: 582
Address: 247 Value HEX: 0x247  Value DEC: 583
Address: 248 Value HEX: 0x248  Value DEC: 584
Address: 249 Value HEX: 0x249  Value DEC: 585
Address: 250 Value HEX: 0x250  Value DEC: 592
Address: 251 Value HEX: 0x251  Value DEC: 593
Address: 252 Value HEX: 0x252  Value DEC: 594
Address: 253 Value HEX: 0x253  Value DEC: 595
Address: 254 Value HEX: 0x254  Value DEC: 596
Address: 255 Value HEX: 0x255  Value DEC: 597
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: S. Petrukhin on November 10, 2020, 12:12:29 am
Do you want to write a binary value conversion table in EEPROM to 3x7 = 21 discrete outputs for displaying it on the led?
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 10, 2020, 12:26:35 am
Do you want to write a binary value conversion table in EEPROM to 3x7 = 21 discrete outputs for displaying it on the led?
No, it will be 3 x 4. 3 BCD outputs to connect to CD4511 7 segment driver.
I'll use just 8 address lines. When they are all high (255) the output of the EPROM will be something like this.

D0  D1  D2  D3     D4  D5  D6  D7     D8  D9  D10  D11
  0    0    1     0      0     1    0    1       0     1     0      1  -- 597 (decimal) / 0x255 (hex)

D0 - D3 connected to 1st CD4511
D4 - D7 connected to 2nd CD4511
D8 - D11 connected to 3rd CD4511

I hope it's more clear now.

I intend to play more with EPROMS and for the next project will be to store instruction for a standard 16x2 LCD. But for every project I need to generate a hex file for the EEPROM.

Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: S. Petrukhin on November 10, 2020, 12:58:13 am
Do you want to write a binary value conversion table in EEPROM to 3x7 = 21 discrete outputs for displaying it on the led?
No, it will be 3 x 4. 3 BCD outputs to connect to CD4511 7 segment driver.
I'll use just 8 address lines. When they are all high (255) the output of the EPROM will be something like this.

D0  D1  D2  D3     D4  D5  D6  D7     D8  D9  D10  D11
  0    0    1     0      0     1    0    1       0     1     0      1  -- 597 (decimal) / 0x255 (hex)

D0 - D3 connected to 1st CD4511
D4 - D7 connected to 2nd CD4511
D8 - D11 connected to 3rd CD4511

I hope it's more clear now.

I intend to play more with EPROMS and for the next project will be to store instruction for a standard 16x2 LCD. But for every project I need to generate a hex file for the EEPROM.

Do you need to display a binary number from 0 to 999 on the indicator using BCD drivers, and transcode BIN - > 3 digits of BCD in EPROM? You can do without EPROM, but if you really need it, then here are the steps, it can be made more compact, I wrote this for clarity:

Code: [Select]
int d1,d2,d3;
uint_16 res;

for (int i=0; i<=999; i++) {
   d1=i  / 100;
   d2=(i - d1*100) / 10;
   d3=i - d1*100 - d2*10;
   res=(d1 << 8) or (d2 << 4) or d3;
   printf("Address: %d\tValue HEX: 0x%X",i,res)
}

And just write the res values to a binary file. The programmer can flash a binary image to EPROM, it is not necessary to do it in HEX format.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: helius on November 10, 2020, 01:28:23 am
I would suggest that the easiest way is to write your file in binary and then write binary to the PROM.
"Hex files" are not actually just hexadecimal numbers, they are one of several specific formats that use commands to put data in specific addresses, and also have check digits. Intel Hex has different commands from Motorola Hex, etc. So you could read the documentation for (e.g.) Intel Hex, decide how to use commands to output your data, generate lines of the appropriate length to the correct addresses, etc etc... Or just write in binary which the TL866 can write verbatim without any other complexity.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 10, 2020, 02:24:25 am
You can use standard gnu tools to create exactly the binary file you want using either assembly language or C.

Create a simple minimal linker script something like this in a file rom_link:

Code: [Select]
OUTPUT_FORMAT(ihex)

MEMORY {
  rom : ORIGIN = 0, LENGTH = 2K
}

SECTIONS {
  .text : {} >rom
}

Then write your ROM values in, for example, assembly language in romdata.S:

Code: [Select]
    .byte 1,2,3,4,5

Then build it:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.S
$ cat romdata
:050000000102030405EC
:00000001FF
$

If you wish, you could put .org 2048 after the .byte to fill the rest of the ROM with zeroes. If you put more data there than was specified in LENGTH in the linker script then the linker will give an error.

Or, you can do it in C, say in romdata.c:

Code: [Select]
char foo[] = {1,2,3,4,5};

Build it in just the same way:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.c
$ cat romdata
:050000000102030405EC
:00000001FF
$

The output file will be the same.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: tszaboo on November 10, 2020, 08:32:07 am
Use a standard way. It is almost always better to use a standard, because there are tools available.
Either write the file as an Intel HEX or a Motorola HEX. And search for a library, then you dont need to reinvent the wheel.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Syntax Error on November 10, 2020, 12:50:07 pm
Do you have a schematic for your circuit?

Just a thought here. From my understanding, the 4511 has a latching/strobe pin which keeps the 7 seg display static or loads the data. So connecting your 4511 drivers direct to a microcontroller only requires 3 GPIO pins for the latching lines and 4 for the BCD lines. You only ever need 4 lines for the BCD, so you can add as many digits as you have spare GPIO pins. The MCU contains the translation table, reads the input number and does the segment loading.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: T3sl4co1l on November 10, 2020, 01:06:33 pm
I like to do these sorts of things in JS.  It's accessible, it's pretty powerful, and it has access to most anything you might need.  You can do it right here even, just hit F12!

Example, copy this one-liner to the console* and run it:

Code: [Select]
window.location = URL.createObjectURL(new Blob(Array.from("Hello World\n"), {type: 'text/plain;charset=utf-8'}));

This creates a "blob" (a container for data), from the data passed in (the "Hello World" string, converted to an array type), of MIME type text/plain (i.e., a text file).  Then makes a URL to it, then sets the window to that URL to instantly view it.  With a little different code, you can download that URL instead, and voila, you can save files of arbitrary (binary) content, just put in your array of data.

This does of course need a JS environment to work, which pretty much anything useful has (JS of some sort is built into every modern OS; file access mechanisms will vary, of course).  You may still be more comfortable with C or whatever, which is fine, and to be fair, it's probably easier to drop some stock HEX formatting code into C, than to port it to JS, if you need it in that format.  But I wouldn't think it's much bother either way.

There's no shortage of ways to do it; BASIC isn't very trendy these days, but would've been a prime choice in prior decades (back when every PC came with a BASIC ROM!), and is pretty easy to write stuff like this.  Python and other high level languages are probably choice today.  Or for the Linux guru, write it all in C, you've always got a compiler there at your fingertips, no problem whatsoever.  Or in bash scripts for that matter... :-DD (Or, I'm not sure you'd want to (or even be able to) do such things with Windows batch files, but PowerShell probably could, for not too much more effort than with other command scripts.)

Tim
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 10, 2020, 09:59:51 pm
You can use standard gnu tools to create exactly the binary file you want using either assembly language or C.

Create a simple minimal linker script something like this in a file rom_link:

Code: [Select]
OUTPUT_FORMAT(ihex)

MEMORY {
  rom : ORIGIN = 0, LENGTH = 2K
}

SECTIONS {
  .text : {} >rom
}

Then write your ROM values in, for example, assembly language in romdata.S:

Code: [Select]
    .byte 1,2,3,4,5

Then build it:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.S
$ cat romdata
:050000000102030405EC
:00000001FF
$

If you wish, you could put .org 2048 after the .byte to fill the rest of the ROM with zeroes. If you put more data there than was specified in LENGTH in the linker script then the linker will give an error.

Or, you can do it in C, say in romdata.c:

Code: [Select]
char foo[] = {1,2,3,4,5};

Build it in just the same way:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.c
$ cat romdata
:050000000102030405EC
:00000001FF
$

The output file will be the same.

Looks like i can generate the file using your method.
I will modify my code to output whatever I want in an array in a c file and that should do the trick. Can't wait for my programmer to test.

@3sl4co1l - Great idea for quick and small projects. Not sure if it will work with 1Mb of data.
@Syntax Error - Yeah, I know that an arduino can do that. Might be a lot cheaper as well. I did play around with arduino but never with parallel EPROMS, so it's time to level up, or down :))

Thank you all so far.

*EDIT: Why is my romdata file different than yours? did you actualy use this line too?
Code: [Select]
char foo[] = {1,2,3,4,5};
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 11, 2020, 12:55:46 am
Quote
*EDIT: Why is my romdata file different than yours? did you actualy use this line too?
Code: [Select]
char foo[] = {1,2,3,4,5};

Different how?

Yes, I tested it both ways. Identical output. I used the native x86_64 gcc and binutils on Linux, but any GNU toolchain should work the same.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 11, 2020, 01:13:26 am
Quote
*EDIT: Why is my romdata file different than yours? did you actualy use this line too?
Code: [Select]
char foo[] = {1,2,3,4,5};

Different how?

Yes, I tested it both ways. Identical output. I used the native x86_64 gcc and binutils on Linux, but any GNU toolchain should work the same.

This is how i have it. The first 2 lines are different. I doubt that it will work like this. The EPROM (D27C210) takes 16bit word on the data lines. Might be good to change char foo to unsigned short foo.
Code: [Select]
ubuntu@ubuntu:~/C$ cat rom_link
OUTPUT_FORMAT(ihex)

MEMORY {
  rom : ORIGIN = 0, LENGTH = 2K
}

SECTIONS {
  .text : {} >rom
}
ubuntu@ubuntu:~/C$ cat romdata.c
char foo[] = {1,2,3,4,5};
ubuntu@ubuntu:~/C$ cat romdata
:10000000040000001000000005000000474E5500ED
:10001000020000C004000000030000000000000017
:050020000102030405CC
:00000001FF
ubuntu@ubuntu:~/C$

Code: [Select]
ubuntu@ubuntu:~/C$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
ubuntu@ubuntu:~/C$
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: T3sl4co1l on November 11, 2020, 07:50:23 am
@3sl4co1l - Great idea for quick and small projects. Not sure if it will work with 1Mb of data.

That's the best part, you have GB of RAM available.  From which the browser might complain after a few hundred megs.  Passing around big arrays is child's play, even with all the interpreter/GC/profiling overhead.

Easily done in C too of course, whether via malloc or memory-mapping a file.  Let the OS handle the heavy lifting for you. :-+

Tim
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 11, 2020, 10:38:04 am
[The EPROM (D27C210) takes 16bit word on the data lines. Might be good to change char foo to unsigned short foo.

That's entirely up to you. Only you know what data you want in the ROM. If you use short then you'll have to make sure you get little-endian vs big-endian correct for your ROM application. If you specify the bytes explicitly (using char) then you know it's correct.

I don't know where those first two lines come from. You didn't show the command(s) you used to create romdata from romdata.c
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: S. Petrukhin on November 11, 2020, 11:14:58 pm
You can use standard gnu tools to create exactly the binary file you want using either assembly language or C.

Create a simple minimal linker script something like this in a file rom_link:

Code: [Select]
OUTPUT_FORMAT(ihex)

MEMORY {
  rom : ORIGIN = 0, LENGTH = 2K
}

SECTIONS {
  .text : {} >rom
}

Then write your ROM values in, for example, assembly language in romdata.S:

Code: [Select]
    .byte 1,2,3,4,5

Then build it:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.S
$ cat romdata
:050000000102030405EC
:00000001FF
$

If you wish, you could put .org 2048 after the .byte to fill the rest of the ROM with zeroes. If you put more data there than was specified in LENGTH in the linker script then the linker will give an error.

Or, you can do it in C, say in romdata.c:

Code: [Select]
char foo[] = {1,2,3,4,5};

Build it in just the same way:

Code: [Select]
$ gcc -nostartfiles -nostdlib -T rom_link -o romdata romdata.c
$ cat romdata
:050000000102030405EC
:00000001FF
$

The output file will be the same.

Looks like i can generate the file using your method.
I will modify my code to output whatever I want in an array in a c file and that should do the trick. Can't wait for my programmer to test.

@3sl4co1l - Great idea for quick and small projects. Not sure if it will work with 1Mb of data.
@Syntax Error - Yeah, I know that an arduino can do that. Might be a lot cheaper as well. I did play around with arduino but never with parallel EPROMS, so it's time to level up, or down :))

Thank you all so far.

*EDIT: Why is my romdata file different than yours? did you actualy use this line too?
Code: [Select]
char foo[] = {1,2,3,4,5};

I wrote you a simple EPROM content generator. Just replace printf with write to file procedure to the eeprom.bin file.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 12, 2020, 09:32:41 pm
So far so good. Thank you all for suggestions. I ended up using the following code. It just works. It outputs a binary file that the minipro accepts and I'm happy with it.
Code: [Select]
#include<stdlib.h>
#include<stdio.h>

unsigned short finalResult();
int split(int length);
FILE *ptr;

unsigned short buffer[65537];
unsigned int tmp = 0;
int digits[3]; //Array to store each digit.

int main() {

//fill the buffer
for (unsigned int i = 0; i < 65536; i++) {
split(i);
tmp = finalResult();
if (i > 255) {
tmp = 0;
}
buffer[i] = tmp;
}

for (unsigned int i = 0; i < 258; i++) {
tmp = buffer[i];
printf("Address: %d\tValue HEX: 0x%X  \tValue DEC: %d\n", i, tmp, tmp);
}

//size_t n = sizeof(buffer)/sizeof(buffer[0]);
ptr = fopen("rom.bin","wb");
fwrite(buffer, 2, 65536, ptr);
fflush(ptr);
fclose(ptr);
return 0;
}

//Split the number into 3 digits and store them in an array.
int split(int input) {
int pos = 0;
while (input > 0) {
  int digit = input % 10;
  digits[pos] = digit; pos++;
  input /= 10;
  }
return pos;
}
//Concatenate the digits each into it's right position.
unsigned short finalResult() {
unsigned short res = ((digits[2] << 8) | digits[1] << 4) | digits[0];
return res;
}

However another problem has arrived. Before waiting for the minipro programmer to come, I made an arduino sketch for an Atmega32 in order to program the EPROM. It works fine but at the address 0 it writes 0xff instead of 0 and I have no idea why... All other addresses and data is fine. The code is messy.
Again, many thanks!
Code: [Select]
#ifndef F_CPU
#define F_CPU  8000000L
#endif

//Necessary librarys.
#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
//#include <"uart.h">

//Port definitions
#define PORT_ADDRESS    PORTC
#define DATA_PORT_LOW PORTA
#define DATA_PORT_HIGH  PORTB
#define VPP_EN            PD6
#define OE                PD5
#define CE                PD4
#define PGM             PD3

//Variables
uint8_t FIRST_ADDRESS = 0x00;
uint8_t LAST_ADDRESS = 0xff;
uint16_t data= 0;
uint16_t buffer[3];

void enterProgramMode();
void exitProgramMode();
void writeData(uint8_t address, uint16_t data);
uint16_t readData(uint8_t address);
unsigned int split(uint16_t input);
uint16_t finalResult();

void setup() {
  Serial.begin(115200);
  //Configure pins
  DDRC = 0xff;            //All pins as  output
  DDRA = 0xff;           
  DDRB |= 1 << PB3 | 1 << PB2 | 1 << PB1 | 1<< PB0;     //Only the first 4bits are used
  DDRD |= 1 << VPP_EN | 1 << OE | 1 << CE | 1 << PGM;     //Set PD6 to PD3 as output
  PORT_ADDRESS = 0;
  DATA_PORT_LOW = 0;
  PORTD = 0;
  _delay_ms(1000);
  Serial.print("Enter programming mode\n");
  enterProgramMode();
  _delay_ms(500);
  for (uint16_t i = FIRST_ADDRESS; i < LAST_ADDRESS + 1; i++) {
      split(i);
      data = finalResult();
      writeData(i, data);
      Serial.print(i);
      Serial.print(" ");
      Serial.print(data);
      Serial.print(" ");
      Serial.print(DATA_PORT_LOW);
     
      Serial.println();
      _delay_ms(10);
  }
  _delay_ms(500);
  exitProgramMode();
 
  //Usless code starts here....
  enterReadMode();
  for (uint16_t i = FIRST_ADDRESS; i < LAST_ADDRESS + 1; i++) {
      data = readData(i);
     
      Serial.print(i);
      Serial.print(" ");
      Serial.print(data);
      Serial.print("  ");
      Serial.print(PINB, BIN);
      Serial.print(" ");
      Serial.print(PINA, BIN);
     
      Serial.println();
      _delay_ms(10);
  }
  Serial.println("DONE!");
  //return 0;
}
void enterProgramMode() {
  PORTD |= 1 << VPP_EN | 1 << CE;
  PORTD &= ~(1 << OE);
  DATA_PORT_LOW = 0;
  DATA_PORT_HIGH = 0;
}

//Usless, dosen't work for now.
void enterReadMode() {
  DDRA &= 0;
  PORTA = 0xff;
  DDRB &= ~ (1 << PORTB3 | 1 << PORTB2 | 1 << PORTB1 | 1 << PORTB0);
  PORTB |=  (1 << PORTB3 | 1 << PORTB2 | 1 << PORTB1 | 1 << PORTB0);
  PORTD = 0;
  PORTD |= 1 << PORTD5 | 1 << PORTD4;
}

void exitProgramMode() {
  PORTD &= ~(1 << VPP_EN | 1 << CE);
  PORTD |= 1 << OE;
}

void writeData(uint8_t address, uint16_t data) {
  uint8_t dataL, dataH;
  dataH = data >> 8;
  dataL = data & 0xff;
 
  PORT_ADDRESS = address;     //Set the address
  _delay_us(100);
  DATA_PORT_LOW = dataL;      //Write lower 8bit
  DATA_PORT_HIGH = dataH;     //Write upper 4bit (or whats left)
  PORTD |= (1 << PGM);          //Toggle PGM pin
  _delay_us(105);
  PORTD &= ~ (1 << PGM);
  _delay_ms(50);
}

//usless function. Dosen't work.
uint16_t readData(uint8_t address) {
  uint8_t dataL;
  uint8_t dataH;
  uint16_t data;
  PORTC = address;
  _delay_ms(20);
  dataL = PINA;
  dataH = PINB;
  data = (dataH << 8) | (dataL & 0xff);
  //data |= dataL & 0xff;
  return data;
}

unsigned int split(uint16_t input) {
  unsigned int pos = 0;
  while (input > 0) {
    int digit = input % 10;
    buffer[pos] = digit; pos++;
    input /= 10; 
  }
  return pos;
}

uint16_t finalResult() {
  uint16_t res = ((buffer[2] << 8) | buffer[1] << 4) | buffer[0];
  return res;
}


void loop() {
  // put your main code here, to run repeatedly:

}
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: T3sl4co1l on November 13, 2020, 07:56:15 am
Does the EPROM datasheet guarantee that a 105us write cycle will suffice?

Often they follow a procedure to partially write, verify, and continue writing until verified.

Tim
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Rue_mohr on November 13, 2020, 03:42:39 pm
This looks good. I have not tried to do 16 bits yet, but if you write your output to a file in binary, you should be fine.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
      int fd;
int n;

 if ((fd = open ( "output.bin", O_CREAT|O_WRONLY|O_TRUNC, 00666)) == -1)  {
    printf("Cant open output file\n");
    return 0;
  }

   //-T-e-s-t-  Production routine
   for (int i = 0; i < 256; i++) {
         split(i);                       
         printf("Address: %d\tValue HEX: 0x%X  \tValue DEC: %d\n", i, finalResult(),n = finalResult());
                       write(fd, &n, 2);
   }

close(fd);

   return 0;
}


when you write the ROM, use a command *like*
./minipro -p 2764@DIP28 -s -w /files/programming/c/lcdmessage/output.bin

minipro does not mention that they support files in binary format.


If you want, I have a way of achiving your goal with less chips, if you are interested, please inquire.

  Rue
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 13, 2020, 08:52:01 pm
Does the EPROM datasheet guarantee that a 105us write cycle will suffice?

Often they follow a procedure to partially write, verify, and continue writing until verified.

Tim

In the datasheet, page 5 it says it's enough. I added more delays and still the same. At address 0, the Atmega writes 0xff in the EPROM or it dose't write anything at all at that address. other addresses are fine.

OE,CE, and PGM are inverted with an cd4049. Instead of 12V on the VPP, I only have around 10V because of the way i switch the voltage on the pin using an optocopler.
Datasheet: https://datasheet.octopart.com/D27C210-200V10-Intel-datasheet-139899587.pdf
hexdump:
Code: [Select]
0000000 ff ff 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0000010 08 00 09 00 10 00 11 00 12 00 13 00 14 00 15 00
0000020 16 00 17 00 18 00 19 00 20 00 21 00 22 00 23 00
0000030 24 00 25 00 26 00 27 00 28 00 29 00 30 00 31 00
0000040 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00
0000050 40 00 41 00 42 00 43 00 44 00 45 00 46 00 47 00
0000060 48 00 49 00 50 00 51 00 52 00 53 00 54 00 55 00
0000070 56 00 57 00 58 00 59 00 60 00 61 00 62 00 63 00
0000080 64 00 65 00 66 00 67 00 68 00 69 00 70 00 71 00
0000090 72 00 73 00 74 00 75 00 76 00 77 00 78 00 79 00
00000a0 80 00 81 00 82 00 83 00 84 00 85 00 86 00 87 00
00000b0 88 00 89 00 90 00 91 00 92 00 93 00 94 00 95 00
00000c0 96 00 97 00 98 00 99 00 00 01 01 01 02 01 03 01
00000d0 04 01 05 01 06 01 07 01 08 01 09 01 10 01 11 01
00000e0 12 01 13 01 14 01 15 01 16 01 17 01 18 01 19 01
00000f0 20 01 21 01 22 01 23 01 24 01 25 01 26 01 27 01
0000100 28 01 29 01 30 01 31 01 32 01 33 01 34 01 35 01
0000110 36 01 37 01 38 01 39 01 40 01 41 01 42 01 43 01
0000120 44 01 45 01 46 01 47 01 48 01 49 01 50 01 51 01
0000130 52 01 53 01 54 01 55 01 56 01 57 01 58 01 59 01
0000140 60 01 61 01 62 01 63 01 64 01 65 01 66 01 67 01
0000150 68 01 69 01 70 01 71 01 72 01 73 01 74 01 75 01
0000160 76 01 77 01 78 01 79 01 80 01 81 01 82 01 83 01
0000170 84 01 85 01 86 01 87 01 88 01 89 01 90 01 91 01
0000180 92 01 93 01 94 01 95 01 96 01 97 01 98 01 99 01
0000190 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02
00001a0 08 02 09 02 10 02 11 02 12 02 13 02 14 02 15 02
00001b0 16 02 17 02 18 02 19 02 20 02 21 02 22 02 23 02
00001c0 24 02 25 02 26 02 27 02 28 02 29 02 30 02 31 02
00001d0 32 02 33 02 34 02 35 02 36 02 37 02 38 02 39 02
00001e0 40 02 41 02 42 02 43 02 44 02 45 02 46 02 47 02
00001f0 48 02 49 02 50 02 51 02 52 02 53 02 54 02 55 02
0000200 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
*
0020000
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Nominal Animal on November 13, 2020, 09:56:43 pm
How about using two Padauk PMS152-S16 (datasheet (http://www.padauk.com.tw/upload/doc/PMS152_datasheet_v105_EN_20200609.pdf); $0.08 at LCSC.com (https://lcsc.com/product-detail/Others_PADAUK-Tech-PMS152-S16_C317590.html)) instead, programming them using the free-pdk (https://github.com/free-pdk/) toolchain and hardware programmer?

Both chips are connected to the same 8 inputs, and 5 of the 10 outputs.  (The two most significant bits of the 12-bit output value are always zero.)

This leaves an extra pin for latch/update, if you want/need one.  (Or, you can extend to 9 bit input and 12-bit output, by supplying only the 7 most significant input bits to the chip providing the most significant 7 output bits.)

The programs themselves are trivial, except that you'll probably want to construct the input and output bit by bit, so you can get an optimal pin layout for your use case.  (In particular, the least significant bit of the input always matches the least significant bit of the output, so at most you need 127 look-up entries.)
Each chip only consumes a couple of mA even running at 16 MHz; for this use case, you can use a much lower frequency, dropping the current consumption under 0.1mA.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 13, 2020, 10:01:58 pm
How about using two Padauk PMS152-S16 (datasheet (http://www.padauk.com.tw/upload/doc/PMS152_datasheet_v105_EN_20200609.pdf); $0.08 at LCSC.com (https://lcsc.com/product-detail/Others_PADAUK-Tech-PMS152-S16_C317590.html)) instead, programming them using the free-pdk (https://github.com/free-pdk/) toolchain and hardware programmer?

Both chips are connected to the same 8 inputs, and 5 of the 10 outputs.  (The two most significant bits of the 12-bit output value are always zero.)

This leaves an extra pin for latch/update, if you want/need one.  (Or, you can extend to 9 bit input and 12-bit output, by supplying only the 7 most significant input bits to the chip providing the most significant 7 output bits.)

The programs themselves are trivial, except that you'll probably want to construct the input and output bit by bit, so you can get an optimal pin layout for your use case.  (In particular, the least significant bit of the input always matches the least significant bit of the output, so at most you need 127 look-up entries.)
Each chip only consumes a couple of mA even running at 16 MHz; for this use case, you can use a much lower frequency, dropping the current consumption under 0.1mA.

This chips are really cheap, they are great for series production. As I read from datasheet they are OTP, one time programming. They are no use for me as i keep making mistakes and i'll need 100s of them  :-//
This isn't anything comercial, just me having too much free time now and trying to build/learn new things. Thank you anyway for the infos..
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 13, 2020, 10:11:18 pm
I got it right! :clap: :clap:
Silly me forgot to connect the EPROM VCC pin to 5V. The breadboard I'm using has the VCC/GND rails split in the middle. Only the one rail for the EEPROM was left unconneted. Thats why the read function didn't work well  :clap: :clap:
But somehow it did work but not as expected. What should I do with the unused data/address pins? should they be pulled low or can they be left floating? the unused address pins are pulled low now, but the data unused data pins are left floating.

EEPROM dump after programming.
Code: [Select]
0000000 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0000010 08 00 09 00 10 00 11 00 12 00 13 00 14 00 15 00
0000020 16 00 17 00 18 00 19 00 20 00 21 00 22 00 23 00
0000030 24 00 25 00 26 00 27 00 28 00 29 00 30 00 31 00
0000040 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00
0000050 40 00 41 00 42 00 43 00 44 00 45 00 46 00 47 00
0000060 48 00 49 00 50 00 51 00 52 00 53 00 54 00 55 00
0000070 56 00 57 00 58 00 59 00 60 00 61 00 62 00 63 00
0000080 64 00 65 00 66 00 67 00 68 00 69 00 70 00 71 00
0000090 72 00 73 00 74 00 75 00 76 00 77 00 78 00 79 00
00000a0 80 00 81 00 82 00 83 00 84 00 85 00 86 00 87 00
00000b0 88 00 89 00 90 00 91 00 92 00 93 00 94 00 95 00
00000c0 96 00 97 00 98 00 99 00 00 01 01 01 02 01 03 01
00000d0 04 01 05 01 06 01 07 01 08 01 09 01 10 01 11 01
00000e0 12 01 13 01 14 01 15 01 16 01 17 01 18 01 19 01
00000f0 20 01 21 01 22 01 23 01 24 01 25 01 26 01 27 01
0000100 28 01 29 01 30 01 31 01 32 01 33 01 34 01 35 01
0000110 36 01 37 01 38 01 39 01 40 01 41 01 42 01 43 01
0000120 44 01 45 01 46 01 47 01 48 01 49 01 50 01 51 01
0000130 52 01 53 01 54 01 55 01 56 01 57 01 58 01 59 01
0000140 60 01 61 01 62 01 63 01 64 01 65 01 66 01 67 01
0000150 68 01 69 01 70 01 71 01 72 01 73 01 74 01 75 01
0000160 76 01 77 01 78 01 79 01 80 01 81 01 82 01 83 01
0000170 84 01 85 01 86 01 87 01 88 01 89 01 90 01 91 01
0000180 92 01 93 01 94 01 95 01 96 01 97 01 98 01 99 01
0000190 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02
00001a0 08 02 09 02 10 02 11 02 12 02 13 02 14 02 15 02
00001b0 16 02 17 02 18 02 19 02 20 02 21 02 22 02 23 02
00001c0 24 02 25 02 26 02 27 02 28 02 29 02 30 02 31 02
00001d0 32 02 33 02 34 02 35 02 36 02 37 02 38 02 39 02
00001e0 40 02 41 02 42 02 43 02 44 02 45 02 46 02 47 02
00001f0 48 02 49 02 50 02 51 02 52 02 53 02 54 02 55 02
0000200 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
*
0020000

Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 13, 2020, 11:34:52 pm
How about using two Padauk PMS152-S16 (datasheet (http://www.padauk.com.tw/upload/doc/PMS152_datasheet_v105_EN_20200609.pdf); $0.08 at LCSC.com (https://lcsc.com/product-detail/Others_PADAUK-Tech-PMS152-S16_C317590.html)) instead, programming them using the free-pdk (https://github.com/free-pdk/) toolchain and hardware programmer?

Both chips are connected to the same 8 inputs, and 5 of the 10 outputs.  (The two most significant bits of the 12-bit output value are always zero.)

This leaves an extra pin for latch/update, if you want/need one.  (Or, you can extend to 9 bit input and 12-bit output, by supplying only the 7 most significant input bits to the chip providing the most significant 7 output bits.)

The programs themselves are trivial, except that you'll probably want to construct the input and output bit by bit, so you can get an optimal pin layout for your use case.  (In particular, the least significant bit of the input always matches the least significant bit of the output, so at most you need 127 look-up entries.)
Each chip only consumes a couple of mA even running at 16 MHz; for this use case, you can use a much lower frequency, dropping the current consumption under 0.1mA.

This chips are really cheap, they are great for series production. As I read from datasheet they are OTP, one time programming. They are no use for me as i keep making mistakes and i'll need 100s of them  :-//
This isn't anything comercial, just me having too much free time now and trying to build/learn new things. Thank you anyway for the infos..

There is a version with flash. It's more expensive, of course, but you only need one of them :-)
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Nominal Animal on November 13, 2020, 11:36:04 pm
When writing the EPROM, I'd add 10k resistors to ground for each unused address and data pin.
When using the EPROM, I'd connect unused address pins to ground, and leave unused data pins floating.

By the way, here's the Arduino sketch I'd use to write the EPROM.  This uses arbitrary pins, and waits for Enter (from Arduino serial monitor) before writing the data.  I wrote it according to the datasheet you linked, and it compiles, but is otherwise untested.  It does the full write-verify-rewrite-if-necessary thing, too, and reports each address written to the serial monitor.  You do need to edit the pin numbers, and whether the logic (EPROM_ constants) match your circuit.
Code: [Select]
// Chip enable, output enable, program, and programming voltage control pins
#define  EPROM_CE    1
#define  EPROM_OE    2
#define  EPROM_PGM   3
#define  EPROM_PDG   4

// Logic used for the above pins
#define  EPROM_CE_LOW   LOW
#define  EPROM_CE_HIGH  HIGH
#define  EPROM_OE_LOW   LOW
#define  EPROM_OE_HIGH  HIGH
#define  EPROM_PGM_LOW  LOW
#define  EPROM_PGM_HIGH HIGH
#define  EPROM_PDG_12V  LOW
#define  EPROM_PDG_5V   HIGH

// Address pins
#define  EPROM_A0    5
#define  EPROM_A1    6
#define  EPROM_A2    7
#define  EPROM_A3    8
#define  EPROM_A4    9
#define  EPROM_A5   10
#define  EPROM_A6   11
#define  EPROM_A7   12

// Data pins
#define  EPROM_D0   13
#define  EPROM_D1   14
#define  EPROM_D2   15
#define  EPROM_D3   16
#define  EPROM_D4   17
#define  EPROM_D5   18
#define  EPROM_D6   19
#define  EPROM_D7   20
#define  EPROM_D8   21
#define  EPROM_D9   22

// Write one word. Returns true if successful, false if failed.
static bool eprom_program(uint8_t address, uint16_t data)
{
    const unsigned char  data_hi = data >> 8,
                         data_lo = data;
    unsigned char        retries = 25;
    unsigned char        lo, hi;

    // Make sure EPROM is in standby, outputs disabled.
    digitalWrite(EPROM_CE, EPROM_CE_LOW);
    digitalWrite(EPROM_OE, EPROM_OE_LOW);

    // Set address.
    digitalWrite(EPROM_A0, (address &   1) ? HIGH : LOW);
    digitalWrite(EPROM_A1, (address &   2) ? HIGH : LOW);
    digitalWrite(EPROM_A2, (address &   4) ? HIGH : LOW);
    digitalWrite(EPROM_A3, (address &   8) ? HIGH : LOW);
    digitalWrite(EPROM_A4, (address &  16) ? HIGH : LOW);
    digitalWrite(EPROM_A5, (address &  32) ? HIGH : LOW);
    digitalWrite(EPROM_A6, (address &  64) ? HIGH : LOW);
    digitalWrite(EPROM_A7, (address & 128) ? HIGH : LOW);

    while (1) {

        // Set output data.
        pinMode(EPROM_D0, OUTPUT); digitalWrite(EPROM_D0, (data_lo &   1) ? HIGH : LOW);
        pinMode(EPROM_D1, OUTPUT); digitalWrite(EPROM_D1, (data_lo &   2) ? HIGH : LOW);
        pinMode(EPROM_D2, OUTPUT); digitalWrite(EPROM_D2, (data_lo &   4) ? HIGH : LOW);
        pinMode(EPROM_D3, OUTPUT); digitalWrite(EPROM_D3, (data_lo &   8) ? HIGH : LOW);
        pinMode(EPROM_D4, OUTPUT); digitalWrite(EPROM_D4, (data_lo &  16) ? HIGH : LOW);
        pinMode(EPROM_D5, OUTPUT); digitalWrite(EPROM_D5, (data_lo &  32) ? HIGH : LOW);
        pinMode(EPROM_D6, OUTPUT); digitalWrite(EPROM_D6, (data_lo &  64) ? HIGH : LOW);
        pinMode(EPROM_D7, OUTPUT); digitalWrite(EPROM_D7, (data_lo & 128) ? HIGH : LOW);
        pinMode(EPROM_D8, OUTPUT); digitalWrite(EPROM_D8, (data_hi &   1) ? HIGH : LOW);
        pinMode(EPROM_D9, OUTPUT); digitalWrite(EPROM_D9, (data_hi &   2) ? HIGH : LOW);

        // Enable chip.
        digitalWrite(EPROM_CE, EPROM_CE_HIGH);
        delayMicroseconds(2);

        // Pulse PGM.
        digitalWrite(EPROM_PGM, EPROM_PGM_HIGH);
        delayMicroseconds(100);
        digitalWrite(EPROM_PGM, EPROM_PGM_LOW);
        delayMicroseconds(2);

        // Change data lines to inputs.
        pinMode(EPROM_D0, INPUT);
        pinMode(EPROM_D1, INPUT);
        pinMode(EPROM_D2, INPUT);
        pinMode(EPROM_D3, INPUT);
        pinMode(EPROM_D4, INPUT);
        pinMode(EPROM_D5, INPUT);
        pinMode(EPROM_D6, INPUT);
        pinMode(EPROM_D7, INPUT);
        pinMode(EPROM_D8, INPUT);
        pinMode(EPROM_D9, INPUT);

        // Enable EPROM outputs; provides verification.
        digitalWrite(EPROM_OE, EPROM_OE_HIGH);
        delayMicroseconds(2);
        lo = (digitalRead(EPROM_D0) == HIGH) ?   1 : 0
           + (digitalRead(EPROM_D1) == HIGH) ?   2 : 0
           + (digitalRead(EPROM_D2) == HIGH) ?   4 : 0
           + (digitalRead(EPROM_D3) == HIGH) ?   8 : 0
           + (digitalRead(EPROM_D4) == HIGH) ?  16 : 0
           + (digitalRead(EPROM_D5) == HIGH) ?  32 : 0
           + (digitalRead(EPROM_D6) == HIGH) ?  64 : 0
           + (digitalRead(EPROM_D7) == HIGH) ? 128 : 0;
        hi = (digitalRead(EPROM_D8) == HIGH) ?   1 : 0
           + (digitalRead(EPROM_D9) == HIGH) ?   2 : 0;
        digitalWrite(EPROM_OE, EPROM_OE_LOW);

        // Put chip in standby.
        digitalWrite(EPROM_CE, EPROM_CE_LOW);
        delayMicroseconds(2);

        // Verified correctly?
        if (lo == data_lo && hi == data_hi)
            return true;

        // No more retries?
        if (!retries--)
            return false;
    }
}

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

    // Make sure EPROM is in Standby mode
    pinMode(EPROM_CE, OUTPUT);
    digitalWrite(EPROM_CE, EPROM_CE_LOW);

    // Make sure programming voltage is OFF (5V)
    pinMode(EPROM_PDG, EPROM_PDG_5V);

    // EPROM data output is disabled
    pinMode(EPROM_OE, OUTPUT);
    digitalWrite(EPROM_OE, HIGH);

    // EPROM is not in program mode
    pinMode(EPROM_PGM, OUTPUT);
    digitalWrite(EPROM_PGM, HIGH);

    // Address lines are always outputs.
    pinMode(EPROM_A0, OUTPUT);
    pinMode(EPROM_A1, OUTPUT);
    pinMode(EPROM_A2, OUTPUT);
    pinMode(EPROM_A3, OUTPUT);
    pinMode(EPROM_A4, OUTPUT);
    pinMode(EPROM_A5, OUTPUT);
    pinMode(EPROM_A6, OUTPUT);
    pinMode(EPROM_A7, OUTPUT);
}

void loop() {
    uint16_t  addr;
    int       c;
    uint8_t   h0, h1, h2;

    // Wait for USB connection, if native USB MCU (Leonardo etc.)
    while (!Serial);

    delay(1000);

    // Consume all pending serial input.
    while (Serial.available())
        Serial.read();

    // Output the prompt.
    Serial.println(F("Press Enter when ready to write ROM."));
    Serial.flush();

    // Consume serial input until newline.
    do {
        c = Serial.read();
    } while (c != '\n' && c != '\r');

    Serial.println(F("Writing EPROM."));
    Serial.flush();
    digitalWrite(EPROM_PDG, EPROM_PDG_12V);
    delayMicroseconds(2);

    // Data construction loops.
    addr = 0;
    for (h2 = 0; h2 < 10; h2++) {
        for (h1 = 0; h1 < 10; h1++) {
            for (h0 = 0; h0 < 10; h0++) {
                if (addr < 256) {
                    const uint16_t  value = h0 | (h1 << 4) | (((uint16_t)h2) << 8);
                    Serial.print(addr, DEC);
                    if (eprom_program(addr, value)) {
                        Serial.println(F(": OK"));
                        Serial.flush();
                        addr++;
                    } else {
                        Serial.println(F(": Failed"));
                        Serial.flush();
                        addr = 257;
                    }
                }
            }
        }
    }
    digitalWrite(EPROM_PDG, EPROM_PDG_5V);

    if (addr == 256) {
        Serial.println(F("EPROM written successfully."));
    } else {
        Serial.println(F("EPROM write failed."));
    }
    Serial.flush();
}
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Nominal Animal on November 14, 2020, 12:00:38 am
This chips are really cheap, they are great for series production. As I read from datasheet they are OTP, one time programming. They are no use for me as i keep making mistakes and i'll need 100s of them  :-//
This isn't anything comercial, just me having too much free time now and trying to build/learn new things. Thank you anyway for the infos..
There is a version with flash. It's more expensive, of course, but you only need one of them :-)
Yes, the Padauk PFS154-S16, which costs $0.10 at LCSC (https://lcsc.com/product-detail/Others_PADAUK-Tech-PFS154-S16_C317613.html), although you must buy them in sets of five.  It's not exact equivalent to the OTP one, but is programmable using the free tools, and I guess $0.20 (for two) is still cheap enough...

Of course, one must also get/build the programmer (https://github.com/free-pdk/easy-pdk-programmer-hardware).  LCSC seems to be out of STM32F072C8T6's, so one would have to source those from Digikey/Mouser/etc.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 14, 2020, 12:23:11 am
Since you're using the runtime-dispatch-on-pin digitalWrite() anyway I'd shorten that program a ton by using:

Code: [Select]
char eprom_a[] = {5, 6, 7, 8, 9, 10, 11, 12};
char eprom_d[] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22};

... and then looping over them instead of unrolling. It'll be slower, but not perceptibly.

Code: [Select]
// Set address.
for (int i=0; i<8; ++i) digitalWrite(eprom_a[i], (address &  (1 << i)) ? HIGH : LOW);

Etc.

(I'm sure you know this .. it's for the OP)
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Nominal Animal on November 14, 2020, 01:24:50 am
It'll be slower, but not perceptibly.
The difference is huge on AVRs using e.g. Teensyduino, as there digitalWrite() (https://github.com/PaulStoffregen/cores/blob/master/teensy/core_pins.h#L825) simplifies to a single instruction if the pin and state are literal constants, three if the pin is a literal constant.  The array/variable version (including when pin numbers are declared as const int instead of macros) uses the slow Arduino jump table approach.

The actual reason for using pin-specific macros, however, is that it makes it much easier to compare the code settings to the breadboard or PCB circuit.  So much so that if I were to change the code to use arrays instead, I'd put the macros, not direct pin numbers, in the array initializer.
 
(I know I would need to check the pins between the board and the code twice, or I'd get at least one wrong.  It might make the code longer than necessary, but it would for sure help me get the entire project right.  I don't know whether others need that sort of thing, though.)



If having the pins change state as close to simultaneously as possible was important, then I'd use a different approach, shadowing the N output pin state registers.  Each data and address bit would correspond to a constant mask (of N bytes), applied iff the corresponding bit is set.  The N output registers take one cycle to set each, so on a 16 MHz AVR, the transition would take 250ns if the pins are across four ports; or 188ns if the pins are across only three ports.  Constructing the new port state would take a couple of dozen cycles, though.
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: brucehoult on November 14, 2020, 02:12:16 am
It'll be slower, but not perceptibly.
The difference is huge on AVRs using e.g. Teensyduino, as there digitalWrite() (https://github.com/PaulStoffregen/cores/blob/master/teensy/core_pins.h#L825) simplifies to a single instruction if the pin and state are literal constants, three if the pin is a literal constant.  The array/variable version (including when pin numbers are declared as const int instead of macros) uses the slow Arduino jump table approach.

In this case, to get speed you probably needed:

Code: [Select]
if (address &   1) digitalWrite(EPROM_A0, HIGH) else digitalWrite(EPROM_A0, LOW);
if (address &   2) digitalWrite(EPROM_A1, HIGH) else digitalWrite(EPROM_A1, LOW);
:

Plus I'd write a macro so I could write:

Code: [Select]
SET_BITPIN(address, EPROM_A, 0);
SET_BITPIN(address, EPROM_A, 1);
:

Or write some Perl/Python/C to generate it. (Oh how I miss LISP macros when I'm programming in something lesser...)
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Rue_mohr on November 14, 2020, 07:00:46 am
always ground unused inputs!

congraduations!
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: Nominal Animal on November 14, 2020, 07:21:30 am
It'll be slower, but not perceptibly.
The difference is huge on AVRs using e.g. Teensyduino, as there digitalWrite() (https://github.com/PaulStoffregen/cores/blob/master/teensy/core_pins.h#L825) simplifies to a single instruction if the pin and state are literal constants, three if the pin is a literal constant.  The array/variable version (including when pin numbers are declared as const int instead of macros) uses the slow Arduino jump table approach.

In this case, to get speed you probably needed:

Code: [Select]
if (address &   1) digitalWrite(EPROM_A0, HIGH) else digitalWrite(EPROM_A0, LOW);
if (address &   2) digitalWrite(EPROM_A1, HIGH) else digitalWrite(EPROM_A1, LOW);
:
Well, not really... this is avr-gcc, after all.  When EPROM_A0 etc. are literal constants, and optimizations are enabled, using the Teensyduino AVR digitalWrite(),
    digitalWrite(EPROM_A0, (address & 1) ? HIGH : LOW);
    digitalWrite(EPROM_A1, (address & 2) ? HIGH : LOW);
    digitalWrite(EPROM_A2, (address & 4) ? HIGH : LOW);
    digitalWrite(EPROM_A3, (address & 8) ? HIGH : LOW);
and
    if (address & 1) digitalWrite(EPROM_A0, HIGH); else digitalWrite(EPROM_A0, LOW);
    if (address & 2) digitalWrite(EPROM_A1, HIGH); else digitalWrite(EPROM_A1, LOW);
    if (address & 4) digitalWrite(EPROM_A2, HIGH); else digitalWrite(EPROM_A2, LOW);
    if (address & 8) digitalWrite(EPROM_A3, HIGH); else digitalWrite(EPROM_A3, LOW);
do compile to the same code – SBRS/SBRC (Skip if Bit in Register is Set/Cleared), RJMP, SBI (Set Bit in I/O register) in one path, and CBI (Clear Bit in I/O register), and a RJMP in SBI or CBI path.

The core Arduino AVR digitalWrite() is much slower, as it does not do that sort of optimization at all.

On say an ATmega32u4, one can use
Code: [Select]
#define  DATA_0  D,3
#define  DATA_1  D,2
#define  DATA_2  D,1
#define  DATA_3  D,0
#define  DATA_4  D,4
#define  DATA_5  C,6
#define  DATA_6  D,7
#define  DATA_7  E,6
#define  DATA_8  B,4
#define  DATA_9  B,5

#define  ADDR_0  F,4
#define  ADDR_1  F,5
#define  ADDR_2  F,6
#define  ADDR_3  F,7
#define  ADDR_4  B,1
#define  ADDR_5  B,3
#define  ADDR_6  B,2
#define  ADDR_7  B,6

// Helper macros
#define  MERGE2_(a, b)          a ## b
#define  MERGE2(a, b)           MERGE2_(a, b)
#define  SET_(prefix,name,bit) (MERGE2(prefix,name) |= 1 << bit)
#define  SET(...)               SET_(__VA_ARGS__)

static volatile unsigned char high_B = 0,
                              high_C = 0,
                              high_D = 0,
                              high_E = 0,
                              high_F = 0;

void set_outputs(const uint8_t addr, const uint16_t data)
{
    unsigned char port_B, port_C, port_D, port_E, port_F;

    port_B = high_B;
    port_C = high_C;
    port_D = high_D;
    port_E = high_E;
    port_F = high_F;

    if (addr &   1) SET(port_, ADDR_0);
    if (addr &   2) SET(port_, ADDR_1);
    if (addr &   4) SET(port_, ADDR_2);
    if (addr &   8) SET(port_, ADDR_3);
    if (addr &  16) SET(port_, ADDR_4);
    if (addr &  32) SET(port_, ADDR_5);
    if (addr &  64) SET(port_, ADDR_6);
    if (addr & 128) SET(port_, ADDR_7);

    if (data &   1) SET(port_, DATA_0);
    if (data &   2) SET(port_, DATA_1);
    if (data &   4) SET(port_, DATA_2);
    if (data &   8) SET(port_, DATA_3);
    if (data &  16) SET(port_, DATA_4);
    if (data &  32) SET(port_, DATA_5);
    if (data &  64) SET(port_, DATA_6);
    if (data & 128) SET(port_, DATA_7);
    if (data & 256) SET(port_, DATA_8);
    if (data & 512) SET(port_, DATA_9);

    PORTB = port_B;
    PORTC = port_C;
    PORTD = port_D;
    PORTE = port_E;
    PORTF = port_F;
}
which sets all data and output pins within five clock cycles (313 ns at 16 MHz), taking about 50 cycles (3.13 µs at 16 MHz) or so, total.  The pin order is completely arbitrary, and won't affect the speed.  The high_X variables need to "shadow" the port registers, containing 1 for non-address/data output pins that should stay high, as well as for input pins where the internal pullup should be enabled.  To be any faster, one needs to rearrange the address and data pins to match the registers.  (These can be found in the microcontroller schematics, or in the Arduino internal headers for that board.)

Unfortunately, this faster method does not play nicely with Arduino libraries, because digitalWrite(non-address/data-pin, HIGH/LOW) and pinMode(any-pin, INPUT/INPUT_PULLUP) do not update the "shadow" values, so it is only really useful if one writes AVR code on bare metal, i.e. using avr-gcc and avr-libc, without external libraries.

(I do not recommend using this faster method, though.  I just wanted to show what I was talking about earlier, if the pins should transition close together, but one wants to use arbitrary pins for each bit.)
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: westfw on November 14, 2020, 11:16:50 am
I would have been lazy and attacked your C program output with some editor macros to convert it to text that looked like a C structure definition with a .section attribute, and then used the standard compiler tools (gcc + objcopy, for gcc) to output just that section to a .hex file.
(or, you know, objcopy would have taken a raw binary file and output a .hex as well, I guess.)
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: georgian on November 14, 2020, 12:57:18 pm
Quick update. I got it all working. I will post the final improved code that you guys suggested. Thank you all for all your support.
https://youtu.be/_Y2V8trDlc0
Title: Re: How to generate HEX/BIN file for eprom using C?
Post by: S. Petrukhin on November 15, 2020, 11:34:27 am
However another problem has arrived. Before waiting for the minipro programmer to come, I made an arduino sketch for an Atmega32 in order to program the EPROM. It works fine but at the address 0 it writes 0xff instead of 0 and I have no idea why... All other addresses and data is fine. The code is messy.

After erasing the EEPROM, all cells contain 0xFF. Your programmer starts writing from address 1, skips 0, and so there remains 0xFF.