Create a 500ns pulse through Arduino Uno/Mega?

Hi!
I’m designing an 8051 flash programmer using Arduino (similar to Willar Programmer)

The problem is AT89S52 (and similar chips) need a 200-500ns pulse to perform chip erase/write functions(pfa attached datasheet pg18).
Can I do that with arduino?

I have tried port manipulation & timer1 but they don’t seem to erase the chip.

The following is the code for the chip erase function:

  /////////////////////...............CHIP ERASE......................///////////////

  Chip::on();
  VPP::on();
  digitalWrite(C1, LOW);
  digitalWrite(C2, LOW);
  digitalWrite(C3, HIGH);
  digitalWrite(C4, LOW);
  digitalWrite(C5, HIGH);
  digitalWrite(RST, HIGH);
  delay(10);
/*
  TCCR1A = ( (1 << COM1A0));
  TCCR1B = ((1 << WGM12) | (1 << CS10));
  TIMSK1 = 0;
  OCR1A = ocr1aval;
  sei();


  delayMicroseconds(100);
  
 TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
*/
/*cli();
PORTB |=  (1 << PB5);
//asm volatile ("NOP");
PORTB |=  (0 << PB5);
//asm volatile ("NOP");
PORTB |=  (1 << PB5);
sei();
*/

cli();

PORTB=0B00000010;
PORTB=0B00000110;
PORTB=0B00000010;
PORTB=0B00000110;
sei();
  delayMicroseconds(100);

  VPP::off();
  Chip::off();

at89s52_ds.pdf (264 KB)

Here, ocr1aval=1 (4MHz) and also tested with other frequencies (didn't work that's why commented).

Any help would be appreciated!!

helium96:
The following is the code for the chip erase function:

Please describe (in plain language) how the code is intended to work. That sort of code is very time-consuming to figure out.

...R

I’m sorry, here’s a commented version of the same code:

  /////////////////////...............CHIP ERASE......................///////////////

  Chip::on(); //turning on AT89S52
  VPP::on(); //turning on 12V power supply
  digitalWrite(C1, LOW); //setting control signal P3.6(Arduino pin 9) to low
  digitalWrite(C2, LOW);  //setting control signal P3.7(Arduino pin 10) to low
  digitalWrite(C3, HIGH); //setting control signal P2.6(Arduino pin 8) to high
  digitalWrite(C4, LOW);  //setting control signal P2.7(Arduino pin 13) to low
  digitalWrite(C5, HIGH); //setting control signal P3.3(Arduino pin 12) to high
  digitalWrite(RST, HIGH); //setting control signal Reset(Arduino pin 3) to high
  delay(10);

////tried pulse through timer 1 set at 4MHz (ocr1aval=1)////

/*
    TCCR1A = ( (1 << COM1A0));
    TCCR1B = ((1 << WGM12) | (1 << CS10));
    TIMSK1 = 0;
    OCR1A = ocr1aval;
    sei();


    delayMicroseconds(100);
  
    TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
*/

////tried pulse through single bit port manipulation with nop for 50%duty cycle////

  /*cli();
  PORTB |=  (1 << PB5);     //PB5 is the ALE/PROG pin on MEGA2560 in my circuit for pulse output 
  asm volatile ("NOP");
  PORTB |=  (0 << PB5);
  asm volatile ("NOP");
  PORTB |=  (1 << PB5);
  sei();
  */

////tried pulse through complete PORTB manipulation////

  cli();

  PORTB=0B00000010;
  PORTB=0B00000110;
  PORTB=0B00000010;
  PORTB=0B00000110;
  sei();
  delayMicroseconds(100);

  VPP::off();
  Chip::off();

Initially, the control signals are set according to the image below (but this is not where I have a problem).

I just want a pulse with a pulse width of 200 to 500ns as a trigger so as to perform chip erase.
How do I get a 200 to 500ns pulse through an Arduino Pin (pin 11, in my case)?

PORTB |= (0 << PB5);

Does not clear PB5. You need “&= ~(1<<PB5)”

The sequence of PORTB writes that isn’t commented out doesn’t modify PB5 at all.
(It pulses PB2…)

Thank you, I just corrected the code.

Still doesn’t seem to work though. :frowning:

  /////////////////////...............CHIP ERASE......................///////////////

  Chip::on(); //turning on AT89S52
  VPP::on(); //turning on 12V power supply
  digitalWrite(C1, LOW); //setting control signal P3.6(Arduino pin 9) to low
  digitalWrite(C2, LOW);  //setting control signal P3.7(Arduino pin 10) to low
  digitalWrite(C3, HIGH); //setting control signal P2.6(Arduino pin 8) to high
  digitalWrite(C4, LOW);  //setting control signal P2.7(Arduino pin 13) to low
  digitalWrite(C5, HIGH); //setting control signal P3.3(Arduino pin 12) to high
  digitalWrite(RST, HIGH); //setting control signal Reset(Arduino pin 3) to high
  delay(10);

////tried pulse through timer 1 set at 4MHz (ocr1aval=1)////

/*
    TCCR1A = ( (1 << COM1A0));
    TCCR1B = ((1 << WGM12) | (1 << CS10));
    TIMSK1 = 0;
    OCR1A = ocr1aval;
    sei();


    delayMicroseconds(100);
  
    TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
*/

////tried pulse through single bit port manipulation with nop for 50%duty cycle////

  cli();
  PORTB |=  (1 << PB5);     //PB5 is the ALE/PROG pin on MEGA2560 in my circuit for pulse output 
  //asm volatile ("NOP");
  PORTB  &= ~(1<<PB5);
  //asm volatile ("NOP");
  PORTB |=  (1 << PB5);
  sei();
  

////tried pulse through complete PORTB manipulation////

  /*
  cli();

  PORTB=0B00000010;
  PORTB=0B00000110;
  PORTB=0B00000010;
  PORTB=0B00000110;
  sei();
  delayMicroseconds(100);
  */
  VPP::off();
  Chip::off();

Two consecutive single bit port writes may give you less than 200ns. Do you have a scope?
Is something setting the pin high before this code? You do want it to be normally high, with the brief low pulse...
An avr clock is 62.5ns, and the CBI should take two cycles ( but I’m not sure when within those two it changes.). You’d want 3 or 4 noops between them, which would give you somewhere between 187.5 and 500 ns between the state changes (but probably 250-375, which would be ok.)

Serial programming might be easier - it’s almost identical to avr programming, so you could use much of the arduinoisp sketch. (I think reset polarity is reversed...)

westfw:
Two consecutive single bit port writes may give you less than 200ns. Do you have a scope?

Tried inserting noops, still doesn't work.
I don't have a scope right now, but I can test the pulse width tomorrow with the scope. I read somewhere on the forums that it takes 6-8 machine cycles for it to switch between high and low.

westfw:
Serial programming might be easier - it’s almost identical to avr programming, so you could use much of the arduinoisp sketch. (I think reset polarity is reversed...)

I know but I'm trying to build a parallel programmer using arduino. This will include chips where serial programming isn't an option (eg. AT89C2051) and only parallel programming works.

You can comfortably use TC1 of Arduino UNO to generate 500ns (0.5 us = 0.5*10-6s) time slot:

1. Configure TC1 as normal up-counter to count 16*106Hz pulses from internal oscillator.

2. 1 clk pulse of the signal of Step-1 will last for 1/16*106 = 0.0000000625 s

3. Therefore, you need to count 8 (0.5*10-6/0.0000000625) pulses to account for the elapse time of 500 ns.

4. The Arduino Codes:

timeDelay()
{
    TCCRA = 0x00;     //normal counter
    TCCRB = 0x00;     //TC1 is OFF
    TCNT1 = 0xFFF8;  //pre-set value for TC1 with clkTC1 = 16 MHz (0x10000 - 0x08 = 0xFFF8)
    TCCRB = 0x01;     //start TC1 with divide factor 1
    while (bitRead(TIFR1, 0) != HIGH)
    {
       ;     //wait until 500 ns has elapsed
    }
    bistSet(TIFR1, 0);   //clear TOV1 (overflow) bit
}

A scope is required for several reasons. The setup and hold times of all signals should be controlled (starting at the input trigger levels), the programming pulse width and also the Vpp pulse levels. Don't forget to wait for a ready signal before applying the next command - chip erase takes about 500ms.

You can toggle a pin but setting the corresponding bit in the PIN register to 1:

// Assume pin is LOW
   PINB = 1<<2;  // Toggle PB2 to HIGH
   PINB = 1<<2;  // Toggle PB2 back to LOW

Because it doesn’t have to do a Read/Modify/Write cycle it might be faster than modifying the PORTB register.

isn’t this easier to accomplish with a bit of hardware? I’m thinking of a 555 monostable but the pulse is too short, but that’s the idea. Edge triggered pulse. Maybe an RC circuit connected to an inverter that can turn it into a nice square pulse. Easy to trigger by a falling or rising edge of the pin signal.

westfw:
Does not clear PB5. You need “&= ~(1<<PB5)”

The sequence of PORTB writes that isn’t commented out doesn’t modify PB5 at all.
(It pulses PB2…)

Practically, all the following four instructions clear the PB5-bit of Port-B Register (tested on UNO).

PORTB =(0<<PB5);  //L is OFF
 PORTB &= (0<<PB5);       //L is OFF
 PORTB = ~(1<<PB5);  //L is OFF
PORTB &= ~(1<<PB5);   //L is OFF

UNO Codes:

void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); //L is ON
  delay(2000);
 // PORTB =(0<<PB5);  //L is OFF
 PORTB &= (0<<PB5);   //L is OFF
 //PORTB = ~(1<<PB5);  //L is OFF
// PORTB &= ~(1<<PB5);   //L is OFF

}

void loop() 
{

}

GolamMostafa:
Practically, all the following four instructions clear the PB5-bit of Port-B Register (tested on UNO).

Well… yes, but you normally want all other bits to remain untouched.

PORTB =(0<<PB5)

That one clears ALL bits of the port, as it’s equivalent to:

PORTB = 0;
PORTB &= (0<<PB5);

Same effect: something & 0 = 0. It clears the complete port.

Then:

PORTB = ~(1<<PB5);

This one sets all other bits to 1, only PB5 to 0.

Finally a correct one:

PORTB &= ~(1<<PB5);

This leaves all pins unaffected, except PB5 which is cleared. That’s what you want.

You can also you use the bitClear() macro for this:

bitClear(PORTB, PB5);

Of course you can accomplish the opposite using the bitSet() macro.

At the risk of going off the current topic but getting to the goal, this is my 89S52/89C2051 programmer:

Less than $10 on eBay. Search for SP200SE.

You can also use one of the eBay $3 USBISP programmers and the old Atmel 89 series studio IDE if you run Windows.

Thanks, I checked with a scope.
The pulse I get by bitBanging using the above methods is 1MHz, but I require at least 2MHz.
Any ideas?

*Sorry for the typo. I meant MHz not kHz. Corrected.

The pulse I get by bitBanging using the above methods is 1kHz, but I require at least 2kHz.

How did we get from needing a 250-500ns pulse, to something in kHz?
I can’t offer any new suggestions without seeing your current code, and telling me just what you’re measuring…

The following test sketch generates pulses of about 375ns on MISO (pin 12, I think) of an Uno.
without the 0.25us delay, the pulses are about 125ns.

#define pin PIN_SPI_MISO   // an easy pin to attach a scope probe to.
#include <util/delay.h>

void setup() {
  pinMode(pin, OUTPUT);
  digitalWrite(pin, 0);
}

void loop() {
  _delay_us(5);
  PORTB |= 1 << PB4;  //  Direct port access for MISO.
  _delay_us(0.25);
  PORTB &= ~(1 << PB4);
}

Thanks for the reply!
It was MHz not kHz, I corrected.

I don’t have access to a scope at all times. Did you test this code with one?

This is my code for that particular purpose (i’m skipping the unnecessary lines before and after):

  cli();
  PORTB |=  (1 << PB5);     //PB5 is the ALE/PROG pin on MEGA2560 in my circuit for pulse output 
   asm volatile ("NOP");

  
  PORTB  &= ~(1<<PB5);
   asm volatile ("NOP");
   asm volatile ("NOP");
   asm volatile ("NOP");


  
  PORTB |=  (1 << PB5);
  sei();

When I tested this with a scope, I get a pulse with about 400ns up time (+ve duty) and 100ns down time (-ve duty). Only after that I included the NOP instructions, each of which consumes 1 machine cycle (62.5ns), to add a delay of 187.5ns when LOW. I need to pulse the signal low for a duration of 200-500ns.

Thanks!

You set PB5 high at the begin and end of your code. One of these can be omitted, because if PB5 is low on entry, your code must have generated a stray pulse on PB5 in between. I’d move the first occurence into setup().