DigitalWrite & DigitalRead and Delay in ns

The 16MHz AVRs can do that timing:


Simulation
method: microseconds/write
digitalWrite for: 3.436
PORTx toggle for: 0.259
PINx toggle for: 0.328
digitalWrite unrolled 100x: 3.273
PORTx toggle unrolled 100x: 0.129
PINx toggle unrolled 100x: 0.066

Many Thanks DaveX, I'm not familiar wokwi but if I understand correctly, I can use an Arduino uC to get the timing I'm looking for.
Can you let me know witch Arduino IC can do the work, does the ATMEGA328 will,
or other affordable uC.
I'm retired, and enjoy building electronics project.
regards.

I looked at wokwi and it's use an Arduino UNO for the simulation
it's mean I can take an ATMEGA328P IC and build a circuit that will work
as per the simulation?

Can I get 2 or more pin work together not one after the other.
to get 1 pin high for 4us and during that time another pin low or high for 500ns.
as example.

Thanks again

The other trick to do with an AVR is to use an 8-bit shift register, or other device, for the upper address bits. Thusly, you don't have to write to that as often, so the overhead is less painful. That would let a stock 28 pin '328 do the job.
Off the top of my head, something like:
D0-D7 - bidirectional data (because these 8 form the only 8 bit port that can be R/W quickly)
D8-D13 - A0-A5 (of the EEPROM)
D14 - clock(for shift register)
D15 - CS - of shift register, if required
D16 -data (for shift register)
D17- OE of EEPROM
D18- WE of EEPROM
D19 - CS of EEPROM
A6 thru A10 of course would be fed by the shift register outputs.
There might be other port optimizations to take advantage of.
You may wish to change processors, I'm just pointing at a possible solution that wouldn't require it. Another solution might be to give the data pins an extra function, writing to an 8-bit latch to form some of the address bits.
It's mostly a matter of how hard you want to sweat a less capable processor, and what time you have available for to work on the finesse.

Hello camsysca,
I read about Ben Eater EEPROM programmer on github, using a nano + shift register
it's very interesting.

Sorry, @jackcable2002, just saw your reply to @DaveX. Yes, quite do-able with '328. Welcome to the 'gray, but not done bitbanging yet' crowd.

for what I can read about the code it's use a 1ms for writing the EEPROM

/*
 * Write a byte to the EEPROM at the specified address.
 */
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, OUTPUT);
  }

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    digitalWrite(pin, data & 1);
    data = data >> 1;
  }
  digitalWrite(WRITE_EN, LOW);
  delayMicroseconds(1);
  digitalWrite(WRITE_EN, HIGH);
  delay(10);
}

Another solution, I think will be to use a 328, and a mm74hc221 to keep the writing under 1us.
As Ben Eater video on Youtube , mention that it's ok to write at around 1us
but this will affect the inner chip on a long run, this is why Atmel datasheet
is a 1us max.

Could be done much leaner, but it's up to you. I'm in the middle of something, but can get back to you later tonight. The key is to

  • take advantage of 8-bit port reads and writes on D0-D7
  • use a register/latch (like a 74ALS374) for 8 bits of address
  • use a register/latch (like a 74ALS374) for (up to) 8 bits of higher address
  • use the remaining data outputs for CS/OE, etc. for the latches and the EEPROM.
  • a bit slower would be to do all the address bits on something like an MCP23017.
    Quite a bit slower, though.

I expect with a bit of finesse, you'd be able to do much better than 1 ms. It's not that hard, just a few fine-tuned routines, and careful pin selection up front. Of course, the code would be model-specific. You won't move the code from a '328 to anything else without some effort.

1 Like

Don't see an advantage. A few lines of port writes and _NOPs are going to make that happen just as easy.

Draw the timing diagram.

  • set address
  • set data
  • drop signal
  • drop signal
  • drop signal(may not be required)
  • raise signal
  • raise signal
  • rinse and repeat
    I just finished writing a quickie routine to write to Neopixels at 1.25 uS per bit, serial, and it's thick with _NOPs to stretch the timing. For your critical part, it should be simple. You really only care about the 3 signal's relationship, the rest of it can take whatever time it takes.
    To guarantee timing, you have to hold off interrupts while you do the critical part. Things like millis(), etc. can otherwise bite, but no big deal.
  • You can get a 62ns pulse with this code, adding NOOPs adds more time.

//62ns pulse on UNO pin 13
#define PULSE62_13 cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()

2 Likes

I see, but I was not familiar with asm _NOP if is what you in mind, but for now I have so much research to do on this topic, I don't want you to waste valuable time for this project. Let me get my mind straight about the direction of this project, I'll do some test circuit and learn before asking anymore for now.
I really appreciate your time and efforts to help me.
regards.

Hello LarryD,
and many thanks for your time and efforts, let me digest all of this info,
and I'll be back on track soon I guess.
I don't know much about NNOPs so i have to lean this before.

regards.

@jackcable2002 No problem, glad you want to 'learn it', not be 'fed it'. We can do it either way, but teaching is more fun. Do NOT hesitate to ask, here, or in a private message. If I don't respond, I'm likely dealing with someone else's question, or, because I'm retired, doing what I, or possibly my better half, thinks is more fun - but, I'll get back to you.
Some of the best reading:

A phenomenal source of the nitty gritty details.

And, for your entertainment, our own @LarryD (a fine Canadian) offers this:

1 Like

Hello camsysca

It's great to get good advice by friendly fellows.

1 Like

Went back and read your first post. You still want this on an R4, or a UNO, or a bare '328, or what? You only wanted 8 ports, but then said

I assumed that a 328 will be short of pin's.

Does that mean you wanted 8 x 8bit ports? Please define clearly the target, don't worry about what you think anything can or can't do.
And, are we writing, reading, copying from one to another, or what? Do we need to receive data from elsewhere, in order to program the EEPROM? Or send data elsewhere that we read from it? Questions, Questions.

Yes it can for both digital i/o and shorter than 1us delays.

If you use a Teensy AVR product, and use constants for the pin# and HIGH and LOW for the values vs a variables, with digitalRead() and digitalWrite(), the teensy code will optimize that down to a single AVR instruction.
This is because the Teensy products supply their own AVR core library.
That was re-written to be better and MUCH faster.
If everything is a constant the slow table lookups that from flash that are in the Arduino.cc avr core library are not used.
This code was offered to Arduino.cc but they declined and did not want to put it into the AVR core.

On the AVR platform you can use the AVR libc delay functions to get sub microsecond delays.
I worked with the AVR libc developers to get this code into the library and to fix the code to make it work correctly with accurate delays.
That said, you can't always get the delay you want but you will get the closest delay that is possible.
Look for <util/delay.h> in the libC library for the fully documenation.

There are other options for other h/w platforms.

--- bill

2 Likes

I came across Ben Eater EEPROM programmer the manual entry one
with dip sw,

then instead of using the R/C circuit to generate the WE/OE pulse
I design one with mm74hc221 witch is more accurate.

Then I try with ATtiny85, 328, Picaxe 20x8, to duplicate the 2 pulses but no luck on that side.

I have a basic experience with Arduino 328p, "digitalwrite etc.. and some
direct port manipulation"

But since I need 2 or maybe 3 pulses working in the same time, I didn't know
how to do it.

the data and address can be generated by internal counter just to get into the EEPROM.
this is a learning platform for (maybe) future project.
If I can keep the overall project simple and easy to understand that's good for me.

For now I'm looking to control the 2 or 3 pulses with an uC, and then I can add control for the data+address.
it's an up going project.

Thanks again for taking the time.

1 Like

Thanks Bill for the info, I'll have to look at that also.

These?

void _delay_loop_1(uint8_t __count)
void _delay_loop_2(uint16_t __count)

https://www.nongnu.org/avr-libc/user-manual/group__util__delay__basic.html