Open
Description
I have the following code, reduced as far as I could:
#include <avr/io.h>
#include <avr/cpufunc.h>
#include <stdbool.h>
#define nanowait() _NOP()
int main ()
{
/* Input trigger: PD0 */
DDRD |= _BV(DDD0);
PORTD |= _BV(PD0);
/* Input trigger: PC0 */
DDRC |= _BV(DDC0);
PORTC |= _BV(PC0);
/* Set up input pin PC5 with pull-up resistor */
DDRC &= ~_BV(DDC5);
PORTC |= _BV(PC5);
/* Debug output: PB0 */
DDRB |= _BV(DDB0);
PORTB &= ~_BV(PB0);
for (;;)
{
/* Read input */
uint8_t x = 0;
PORTD &= ~_BV(PD0);
PORTC &= ~_BV(PC0);
nanowait();
x = PINC;
PORTD |= _BV(PD0);
PORTC |= _BV(PC0);
x = (~x & _BV(PC5)) ? 1 : 0;
/* Write out result to debug port */
if (x)
PORTB |= _BV(PB0);
else
PORTB &= ~(_BV(PB0));
}
}
What it tries to do, is to pulse low PD0
and PC0
before reading in some input on PC5
. Originally, this came up in the context of a 4x4 keypad where there are four row selectors and four column readers, but the problem can be shown even on this smaller example.
In SimAVR, I set PC5
in response to PD0
going low:
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "sim_avr.h"
#include "avr_ioport.h"
#include "sim_elf.h"
void debug_cb(struct avr_irq_t* irq, uint32_t value, void* closure)
{
printf("PIN%s%d = %d\n", (char*)closure, irq->irq, value);
}
int count = 0;
void selector_cb(struct avr_irq_t* irq, uint32_t value, void* closure)
{
avr_irq_t* output = (avr_irq_t*)(closure);
if (value) return;
if (++count == 7)
{
avr_raise_irq(output, false);
count = 0;
} else {
avr_raise_irq(output, true);
}
}
int main(int argc, char *argv[])
{
elf_firmware_t f;
elf_read_firmware("image.elf", &f);
f.frequency = 16e6;
const char *mmcu = "atmega328p";
avr_t * avr = avr_make_mcu_by_name(mmcu);
if (!avr)
return 1;
avr_init(avr);
avr_load_firmware(avr, &f);
const char* keypadName = "keypad";
avr_irq_t *keypad = avr_alloc_irq(&(avr->irq_pool), 0, 1, &keypadName);
/* Input selector PD0 */
avr_irq_register_notify(
avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 0),
selector_cb, keypad);
/* Input signal PC5 */
avr_connect_irq(keypad, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 5));
/* Debug output PB0 */
avr_irq_register_notify(
avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 0),
debug_cb, "B");
for (;;)
{
avr_run(avr);
}
}
If I run this, I see that the debug output on PB0
never goes high.
However, if I comment out the line PORTC &= ~_BV(PC0);
i.e. I don't write to PORTC
before reading PINC
, then it works as expected and I see PB0
changing between 0 and 1.
Metadata
Metadata
Assignees
Labels
No labels