3

I'm thinking of creating a "small" electronic dice. (I will solder the button a little different though xD)

enter image description here

But there are some concerns on my design:

Powering from a coin-cell

It's a 5V arduino Pro mini, but it should be able to run (per datasheet) on 2.7V to 5.5V, can I just put the 3V of the coin-cell battery on VCC. (I'm aware I'll have to use the internal 8Mhz clock on this voltage though). I won't need the regulator, since the coin-cell will never exceed 5V?

Can I use a I/O as (input/supply) GND?

You can actually use outputs as positive voltage, and you can sink currents. But does that mean I can connect the negative side of the coin-cell to an output, and sink it? This way it should power my arduino's VCC pin through the "digital GND"

Using the reset button

I could use the reset button, but would it still give me "random enough" numbers? Since the seed is reset every time?

(I probably won't use it though, it's placed inconveniently for this project, but I am wondering.)

A crude drawing below:

The fun thing is, polarity of the LED's/segments doesn't matter, since I can change which side is high or low? :) Also, I've only drawn half the LED's/segments. And I know it's better to use a resistor on every pin, but I don't want to make it any more bulky.

(btw, battery GND pin should be pin 4, not pin 2)

enter image description here

7

Can I use a I/O as (input/supply) GND?

You can use an I/O pin as a supply for another (low power) device, but you should power the Arduino itself from its Vcc and GND pins.

I could use the reset button, but would it still give me "random enough" numbers?

You will likely see the very same sequence every time you reset it. There are ways around this:

  • You can seed the random number generator (RNG) at startup with an analogRead() from an unconnected pin, but it's not clear how much entropy you can expect from this.
  • You can save the RNG's entropy into the .noinit memory section, this way it will not be wiped up during the program startup.

I would recommend, however, that you use a normal I/O pin to trigger the dice, if only for one reason: the time when the user presses the button (that you read with micros()) is a very good entropy source for seeding the RNG.

For example, whenever the user presses the button you could:

srandom(random() ^ ((uint32_t) analogRead(0) << 22) ^ micros());

This way you combine the entropy from the button press with the entropy from the analog pin (if any), with whatever entropy may already by in the RNG.

Edit: More on entropy gathering.

As you seemingly already know, random() is a pseudo-random number generator intended to produce a sequence of numbers that look random. Unless you have some other source of randomness in your program, every time you restart the Arduino you will get the very same sequence of numbers. Getting true randomness (also called “entropy”) on an Arduino is not so easy. Here are some ideas you may want to explore.

Read from an unconnected analog input

This trick seems to be pretty popular. It can even be found in the Arduino documentation on randomSeed():

use randomSeed() to initialize the random number generator with a fairly random input, such as analogRead() on an unconnected pin.

In my experience, this seems to be a very poor entropy source. I wrote a test program that prints out the output of analogRead(0) and it seems to cycle through the same few values in an almost predictable way. I estimate this gives around one or two bits of entropy per call. On the plus side, each call takes just over 100 µs.

Read from an analog noise source

There is a lot of literature on building analog noise sources. Such sources are used inside crypto-grade random number generators, but the circuits are likely to be more complex than you would like. There seems, however, to be a very simple alternative. In a comment to this post, CharlieHanson wrote:

Connecting the analogue input to the collector of a run-of-the-mill transistor, with the emitter grounded and base open helps to make a noisy input.

I have not tested this idea, but it is certainly worth exploring.

Time user input

If the user is required to press a button to throw the dice, the timing of the button press is probably the best entropy source you can have. With a 8 MHz clock, the micros() function has a resolution of 8 µs (64 clock cycles). Assuming the user is unable to control his timing better than 0.1 seconds, then you have more than 13 bits of entropy per button press.

If, instead of micros(), you use timer 1 running at the full CPU speed, then you would have 16 bits of entropy per button press. And you would not need random() at all, as you could just output 1+TCNT1%6. That would be like throwing a dart at a carnival wheel spinning at 80 million RPM (8 MHz / 6)!

Measure clock drift

The drift of a clock relative to another clock can be used as an entropy source. The ATmega chip in your Arduino has two independent clocks: the internal “calibrated” 8 MHz RC oscillator, and the 128 kHz oscillator used by the watchdog timer. Both are low-accuracy clocks subject to somewhat unpredictable drift, which is a good thing for this application. You can gather entropy from this by configuring the watchdog timer as a periodic interrupt source, and using timer 1 at full speed to time the interrupt arrival times:

#include <avr/wdt.h>
#include <util/atomic.h>

// Configure Timer 1 for counting CPU cycles and the watchdog as an
// interrupt source firing (roughly) once a second. Call once in
// setup().
void configure_timers()
{
    // Timer 1.
    TCCR1A = 0;          // normal counting mode
    TCCR1B = _BV(CS10);  // prescaler = 1

    // Watchdog. This is a timed sequence.
    ATOMIC_BLOCK(ATOMIC_FORCEON) {
        WDTCSR = _BV(WDCE)  // enable changing the prescaler
               | _BV(WDE);  // ditto
        WDTCSR = _BV(WDIF)  // clear interrupt flag
               | _BV(WDIE)  // enable interrupts
               | WDTO_1S;   // timeout ~ 1 second
    }
}

volatile uint16_t wdt_time;
volatile bool wdt_fired;

// Watchdog interrupt service routine.
ISR(WDT_vect)
{
    wdt_time = TCNT1;
    wdt_fired = true;
}

// Add entropy to the RNG from the timing of the last WDT interrupt.
// Call periodically in loop().
void get_wdt_entropy()
{
    if (!wdt_fired) return;  // No WDT event since last time.
    uint16_t wdt_time_copy;
    ATOMIC_BLOCK(ATOMIC_FORCEON) {
        wdt_time_copy = wdt_time;
        wdt_fired = false;
    }
    srandom(random() ^ wdt_time_copy);
}

I have tested this idea by plotting the time differences between successive interrupts. On an Arduino Uno clocked at 16 MHz, I see short-time fluctuations with an amplitude of about 300. That should provide around 8 bits of entropy per second.

Save the entropy pool across reboots

Once you have spent some effort to gather entropy from the environment, it would be a pity to lose it all at power down. It is common practice to save the entropy pool to disk when a computer shuts down, and restore it at boot time. This avoids the problem of the RNG always starting in the same predictable state. On the Arduino, you have no disk, but you can use the EEPROM instead. The problem is you cannot know in advance when the user is going to switch the device off. Then, ideally, you would save the entropy every time the user requests a new dice value. The new problem is that the EEPROM is only guaranteed to work reliably for 100,000 write/erase cycles. This may not be a serious problem (100,000 is plenty of throws), but it can nonetheless be mitigated by using a wear-leveling scheme, where you distribute the writes across the whole EEPROM instead of always overwriting the same bytes.

Wear-leveling can add significant complexity to your program, but it turns out there is, in this particular case, a wear-leveling scheme that is trivial to implement: just write at a random location! At startup, you do not know what was the last location written to, but you do not need to: you read and mix the whole contents of the EEPROM:

#include <avr/eeprom.h>

// Save the entropy to EEPROM. Call this every time the user requests a
// new value.
void save_entropy()
{
    uint32_t *address = (uint32_t *)(random() & E2END & ~3);
    eeprom_write_dword(address, random());
}

// Restore the entropy from the EEPROM. Call once in setup().
void restore_entropy()
{
    uint32_t seed = 0;
    for (uint32_t *address = 0; address < (uint32_t *) E2END; address++)
        seed ^= eeprom_read_dword(address);
    srandom(seed);
}

Combine the entropy sources with the XOR operator

As you probably already noticed, the bitwise xor operator (^) is used every time one wants to combine entropy sources. The main reason is that, if a and b are independent random variables, then a^b is at least as random as the most random of a and b. Which means that XORing a “good” random variable with a “bad” one is harmless. This is somewhat formalized as the piling-up lemma.

As an example, doing randomSeed(analogRead(0)) at program startup is fine, but doing it repeatedly during program execution is a terrible idea: most of the time this will put the RNG in one of a very few states. If instead you

srandom(random() ^ analogRead(0));

then you are combining the current randomness of the RNG with the output of analogRead(), and putting this back into the RNG. And this is harmless even if analogRead() is quite predictable.

A side note on randomSeed(): Arduino releases prior to 1.6.5 had a bug that would truncate to 16 bits the entropy provided with randomSeed(). On those releases it is better to use the avr-libc srandom() function. The bug has since been fixed.

2

It's a 5V arduino Pro mini, but it should be able to run (per datasheet) on 2.7V to 5.5V, can I just put the 3V of the coin-cell battery on VCC. (I'm aware I'll have to use the internal 8Mhz clock on this voltage though). I won't need the regulator, since the coin-cell will never exceed 5V?

That is correct.

You can actually use outputs as positive voltage, and you can sink currents. But does that mean I can connect the negative side of the coin-cell to an output, and sink it? This way it should power my arduino's VCC pin through the "digital GND"

Definitely not. That is a sure-fire way to kill the Arduino.

Also you have a Catch-22 situation. To make the pin conduct to ground you have to set it to output and switch it LOW. How can you do that if the chip is powered off? You need to power the chip on in order to power the chip on. It just can't work.

I could use the reset button, but would it still give me "random enough" numbers? Since the seed is reset every time?

You will only get random numbers if you seed the PRNG with a random number. If you can get a source of entropy (noise on an analog pin for instance) then yes, that could work.

And I know it's better to use a resistor on every pin, but I don't want to make it any more bulky.

It's not "better" - it's REQUIRED. With just one resistor and one segment on that segment will get 8x the current compared to having all 8 segments on. You then either get very dim segments with lots on, or smoke from segments when not many are on.

  • 1
    Hmm, and what if I loop through all segments rapidly, having only one on at the time? Then one resistor should do? Since it makes it much easier to wire. Or I should indeed accept the difference and very dim with all on? – Paul Mar 21 '16 at 21:21
  • 1
    If you only have one segment on at a time then yes you can get away with one resistor. – Majenko Mar 21 '16 at 21:22
  • 1
    Yup, that's a nice "hack". Equal brightness, efficient power usage. The trick for randomness is also a good one. If using milis and resetting device, it wouldn't be smart, since milis will the almost always be the same? Is it good to reseed once in a while? – Paul Mar 21 '16 at 21:28
  • It can increase your randomness, yes. Especially if you reseed at random times ;) – Majenko Mar 21 '16 at 21:29
  • 1
    Hmm, yeah when using time as a "random variable" you should avoid seeding at specific times :) I could also try running it and collecting the data, test different methods, should be interesting. – Paul Mar 21 '16 at 21:33
1

Yes you should be fine with the voltage from a coin cell - though don't expect it to last long!

No you can't use an I/O as ground - they are set to input by default, and even if they weren't, if wouldn't be guaranteed to work, and even if it did happen to work*, it would be horrible. I don't quite understand why you want to do it this way - why not just connect the cell's -ve to the GND pin, right next to the VCC?

If you seed your random number generator suitably (e.g. from an unconnected analogue input) you ought to be OK since that will suitably random - you'll be reseeding it each time with a different seed.

*Stranger things have happend! The very fist ARM chip worked without power, running from parasitic currents from the inputs, as they discovered by mistake when they tested it with the power supply disconnected.

  • The reason was that when just inserting the coincell holder, the other pin could only land on an IO pin. Or I would need some wiring. It should only show the digit for a short time when pressed on the button. But what battery is most energy per size? – Paul Mar 21 '16 at 21:24
  • I should look up the battery voltages by myself, sorry. Might even use USB power bank, but doesn't really look small. And might put it in proper board indeed. – Paul Mar 21 '16 at 21:39
  • Ah, that's a coin cell holder in the photo! I thought it was something you'd rested it on to take the picture! :-) Bear in mind that you're probably going to want an off switch, unless you want to take the battery out, so maybe you can wire that in neatly somehow. – Mark Smith Mar 21 '16 at 21:53
  • Yeah, when I look at the picture again, it actually looks awfull. I'm ging to use a protoboard as backplate and probably 2 digits (for other games). An on/off switch is indeed better. And maybe even 2xAA – Paul Mar 21 '16 at 21:55
0

You can actually use outputs as positive voltage, and you can sink currents. But does that mean I can connect the negative side of the coin-cell to an output, and sink it? This way it should power my arduino's VCC pin through the "digital GND"

It would not be a good idea to use a input pin as they can only sink a maximum of 40mA per pin.

Also, incase any power surges are experienced and it is connected to Vcc if that 5v is exceeded then it could damage your board. It might be a better solution to use the RAW pin even if it does ultimately use more power.

  • I agree on not using a digital pin as GND. But, the RAW pin needs a higher voltage? And a power surge from a battery is some what unlikely? – Paul Apr 23 '16 at 20:11
  • 1
    Not from a battery as such however since the design is exposed and open to surrounding sources of static charge it could affect the boards operation – KHS Apr 23 '16 at 20:12
  • Good point, though any static charge on the 5V/GND pins may cause failure? But it indeed is more likely to happen (like when touching the battery if it's connected). But the RAW pin has ESD protection? – Paul Apr 23 '16 at 20:17
  • I think a simple (and aesthetically pleasing) solution would be a case for the whole design. This would mean it could use the 3.3v VCC pin which would use less power compared to the RAW pin. – KHS Apr 23 '16 at 20:21
  • True, but I don't have a laser-cutter or 3D printer ;) I might design a case and let it print by one of those online 3D print services. – Paul Apr 24 '16 at 5:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.