void DoSpiTx(char port, char *string) { SPI_t *Port; switch(port) { case 'c': Port = (SPI_t*)_SFR_IO_ADDR(SPIC); break; case 'd': Port = (SPI_t*)_SFR_IO_ADDR(SPID); break; case 'e': Port = (SPI_t*)_SFR_IO_ADDR(SPIE); break; default: Error("Illegal port"); return; // if no valid port, return }; while(*string != 0) { Port->DATA = *string++; if(!(Port->STATUS&(1<<7))) while(!(Port->STATUS & (1<<7))); // wait for TX complete Port->STATUS |= (1<<7); // clear TX interrupt flag }; };
// ----------------------------------------------------------------------------- // init_channels // ----------------------------------------------------------------------------- inline void init_channels() { // hardcoded ports and pins // use _SFR_IO_ADDR(PORTA) + 32 for ports // and ~(1<<pinnumber) for pins // servo.stop = base value - (x * 12MHz) / 22 // where x is the time you want added to 400us SET(PORTD, PD5); uint8_t i = 0; for (i = 0; i < 8; ++i) { servo_channels[i].servo.stopbytes[1] = eeprom_read_byte(i<<1); servo_channels[i].servo.stopbytes[0] = eeprom_read_byte((i<<1) + 1); // servo_channels[i].servo.stop = ((ASM1700HI<<8)|(ASM1700LO)) - MIDPULSE; servo_channels[i].port = _SFR_IO_ADDR(PORTA) + 32; servo_channels[i].pin = ~(1<<i); } for (i = 8; i < SERVO_AMOUNT; ++i) { servo_channels[i].servo.stopbytes[1] = eeprom_read_byte(i<<1); servo_channels[i].servo.stopbytes[0] = eeprom_read_byte((i<<1) + 1); // servo_channels[i].servo.stop = ((ASM1700HI<<8)|(ASM1700LO)) - MIDPULSE; servo_channels[i].port = _SFR_IO_ADDR(PORTC) + 32; servo_channels[i].pin = ~(1<<(i - 6)); } DDRA = 0xFF; PORTA = 0x00; DDRC |= (1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5); PORTC &= ~((1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5)); // servo_channels[0].servo.stop = ((ASM1700HI<<8)|(ASM1700LO)) - 328; CLR(PORTD, PD5); // TODO add offsets per pin based on their pos in cycle }
void DoSpiConfig(char port, unsigned int div) { SPI_t *Port; switch(port) { case 'c': Port = (SPI_t*)_SFR_IO_ADDR(SPIC); PORTC.DIR |= (1<<4) | (1<<5) | (1<<7); break; case 'd': Port = (SPI_t*)_SFR_IO_ADDR(SPID); PORTD.DIR |= (1<<4) | (1<<5)| (1<<7); break; case 'e': Port = (SPI_t*)_SFR_IO_ADDR(SPIE); PORTE.DIR |= (1<<4) | (1<<5)| (1<<7); break; default: Error("Illegal port"); return; // if no valid port, return }; Port->CTRL = 0x50 | (div & 0x3); };
ISR (WDT_vect, ISR_NAKED){ //will occur after 4 seconds of displaying the current number. asm( "sbi %0,%1 \n\t" //This operation won't affect SREG and will make a noticable change to the register "reti \n\t" //return from interrupt : : "I" (_SFR_IO_ADDR(watchdogTimeout)), "I" (watchdogFlagBit) ); }
void servoTest(void) { u08 pos; u08 channel; // do some examples // initialize RC servo system servoInit(); // setup servo output channel-to-I/Opin mapping // format is servoSetChannelIO( CHANNEL#, PORT, PIN ); servoSetChannelIO(0, _SFR_IO_ADDR(PORTC), PC0); servoSetChannelIO(1, _SFR_IO_ADDR(PORTC), PC1); servoSetChannelIO(2, _SFR_IO_ADDR(PORTC), PC2); servoSetChannelIO(3, _SFR_IO_ADDR(PORTC), PC3); // set port pins to output outb(DDRC, 0x0F); pos = 0; #define SPEED_SERVO 1 // spin servos sequentially back and forth between their limits while(1) { for(channel=0; channel<SERVO_NUM_CHANNELS; channel++) { for(pos=0; pos<SERVO_POSITION_MAX; pos++) { servoSetPosition(channel,pos); timerPause(SPEED_SERVO); } } for(channel=0; channel<SERVO_NUM_CHANNELS; channel++) { for(pos=SERVO_POSITION_MAX; pos>=1; pos--) { servoSetPosition(channel,pos); timerPause(SPEED_SERVO); } } } }
int DoOutput(char port, unsigned int pin, unsigned int val) { PORT_t *Port; switch(port) { case 'a': Port = (PORT_t*)_SFR_IO_ADDR(PORTA); break; case 'b': Port = (PORT_t*)_SFR_IO_ADDR(PORTB); break; case 'c': Port = (PORT_t*)_SFR_IO_ADDR(PORTC); break; case 'd': Port = (PORT_t*)_SFR_IO_ADDR(PORTD); break; case 'e': Port = (PORT_t*)_SFR_IO_ADDR(PORTE); break; case 'f': Port = (PORT_t*)_SFR_IO_ADDR(PORTF); break; default: return -1; // if no valid port, return }; };
//! initializes software PWM system void servoInit(void) { u08 channel; // disble the timer1 output compare A interrupt cbi(TIMSK, OCIE1A); // set the prescaler for timer1 timer1SetPrescaler(TIMER_CLK_DIV256); // attach the software PWM service routine to timer1 output compare A timerAttach(TIMER1OUTCOMPAREA_INT, servoService); // enable and clear channels for(channel=0; channel<SERVO_NUM_CHANNELS; channel++) { // set minimum position as default ServoChannels[channel].duty = SERVO_MIN; // set default port and pins assignments ServoChannels[channel].port = _SFR_IO_ADDR(SERVO_DEFAULT_PORT); //ServoChannels[channel].port = (unsigned char)&SERVO_DEFAULT_PORT; ServoChannels[channel].pin = (1<<channel); // set channel pin to output // THIS IS OBSOLETED BY THE DYNAMIC CHANNEL TO PORT,PIN ASSIGNMENTS //outb(SERVODDR, inb(SERVODDR) | (1<<channel)); } // set PosTics ServoPosTics = 0; // set PeriodTics ServoPeriodTics = SERVO_MAX*9; // set initial interrupt time u16 OCValue; // read in current value of output compare register OCR1A OCValue = inb(OCR1AL); // read low byte of OCR1A OCValue += inb(OCR1AH)<<8; // read high byte of OCR1A // increment OCR1A value by nextTics OCValue += ServoPeriodTics; // set future output compare time to this new value outb(OCR1AH, (OCValue>>8)); // write high byte outb(OCR1AL, (OCValue & 0x00FF)); // write low byte // enable the timer1 output compare A interrupt sbi(TIMSK, OCIE1A); }
int DoInput(char port, unsigned int pin) { PORT_t *Port; switch(port) { case 'a': Port = (PORT_t*)_SFR_IO_ADDR(PORTA); break; case 'b': Port = (PORT_t*)_SFR_IO_ADDR(PORTB); break; case 'c': Port = (PORT_t*)_SFR_IO_ADDR(PORTC); break; case 'd': Port = (PORT_t*)_SFR_IO_ADDR(PORTD); break; case 'e': Port = (PORT_t*)_SFR_IO_ADDR(PORTE); break; case 'f': Port = (PORT_t*)_SFR_IO_ADDR(PORTF); break; default: return -1; // if no valid port, return }; if(pin > 7) { return -1; }; Port->DIR &= ~(1<<pin); // configure port as input if(Port->IN & (1<<pin)) return 1; else return 0; };
void shiftDmxOut(int pin, int theByte) { int port_to_output[] = { NOT_A_PORT, NOT_A_PORT, _SFR_IO_ADDR(PORTB), _SFR_IO_ADDR(PORTC), _SFR_IO_ADDR(PORTD) }; int portNumber = port_to_output[digitalPinToPort(pin)]; int pinMask = digitalPinToBitMask(pin); // the first thing we do is to write te pin to high // it will be the mark between bytes. It may be also // high from before _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask; delayMicroseconds(10); // disable interrupts, otherwise the timer 0 overflow interrupt that // tracks milliseconds will make us delay longer than we want. cli(); // DMX starts with a start-bit that must always be zero _SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask; // we need a delay of 4us (then one bit is transfered) // this seems more stable then using delayMicroseconds asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); for (int i = 0; i < 8; i++) { if (theByte & 01) { _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask; } else { _SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask; } asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); theByte >>= 1; } // the last thing we do is to write the pin to high // it will be the mark between bytes. (this break is have to be between 8 us and 1 sec) _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask; // reenable interrupts. sei(); }
constexpr RegisterConfig(volatile uint8_t ®, const uint8_t value) : _u8RegNr{static_cast<uint8_t>(_SFR_IO_ADDR(reg))}, _u8RegValue{value} {}
void DoUsartTx(char port, unsigned int num, char *string) { USART_t *Port; if(num==0) { switch(port) { case 'c': Port = (USART_t*)_SFR_IO_ADDR(USARTC0); PORTC.DIR |= (1<<3); break; case 'd': Port = (USART_t*)_SFR_IO_ADDR(USARTD0); PORTD.DIR |= (1<<3); break; case 'e': Port = (USART_t*)_SFR_IO_ADDR(USARTE0); PORTE.DIR |= (1<<3); break; case 'f': Port = (USART_t*)_SFR_IO_ADDR(USARTF0); PORTF.DIR |= (1<<3); break; default: Error("Illegal port"); return; // if no valid port, return }; } else if(num==1) { switch(port) { case 'c': Port = (USART_t*)_SFR_IO_ADDR(USARTC1); PORTC.DIR |= (1<<7); break; case 'd': Port = (USART_t*)_SFR_IO_ADDR(USARTD1); PORTD.DIR |= (1<<7); break; case 'e': Port = (USART_t*)_SFR_IO_ADDR(USARTE1); PORTE.DIR |= (1<<7); break; case 'f': Port = (USART_t*)_SFR_IO_ADDR(USARTF1); PORTF.DIR |= (1<<7); break; default: Error("Illegal port"); return; // if no valid port, return }; } else { Error("Illegal port num"); return; }; while(*string != 0) { Port->DATA = *string++; if(!(Port->STATUS&USART_DREIF_bm)) while(!(Port->STATUS & USART_TXCIF_bm)); // wait for TX complete Port->STATUS |= USART_TXCIF_bm; // clear TX interrupt flag }; };
// PD6 12| |17 PB3 // PD7 13| |16 PB2 // PB0 14| |15 PB1 // +----+ #define NUM_PINS 28 #define NUM_PORTS 4 #define PB 2 #define PC 3 #define PD 4 int port_to_mode[NUM_PORTS + 1] = { NOT_A_PORT, NOT_A_PORT, _SFR_IO_ADDR(DDRB), _SFR_IO_ADDR(DDRC), _SFR_IO_ADDR(DDRD), }; int port_to_output[NUM_PORTS + 1] = { NOT_A_PORT, NOT_A_PORT, _SFR_IO_ADDR(PORTB), _SFR_IO_ADDR(PORTC), _SFR_IO_ADDR(PORTD), }; int port_to_input[NUM_PORTS + 1] = { NOT_A_PORT, NOT_A_PORT,