commit 8451542a6fd26d3c81f516aaca915ba6e7939cf0 Author: Maciej Bowszys Date: Tue Dec 9 16:03:16 2025 +0100 251209 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5600db4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +recv/pixmod_recv_1v0/build diff --git a/recv/pixmod_recv_1v0/CMakeLists.txt b/recv/pixmod_recv_1v0/CMakeLists.txt new file mode 100644 index 0000000..1e6cbe5 --- /dev/null +++ b/recv/pixmod_recv_1v0/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_C_COMPILER avr-gcc) +set(CMAKE_CXX_COMPILER avr-g++) + +project(ATtiny45NeoPixel C CXX) + +set(MCU "attiny45") +set(F_CPU 8000000) +set(AVRDUDE_PROGRAMMER "arduino") +set(AVRDUDE_PORT "/dev/ttyACM1") +set(AVRDUDE_BAUDRATE 115200) + +set(CMAKE_C_FLAGS "-Wall -Os -mmcu=${MCU} -DF_CPU=${F_CPU}UL") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -fno-exceptions -fno-rtti") +set(CMAKE_EXE_LINKER_FLAGS "-Wl,-gc-sections -mmcu=${MCU}") + +set(SOURCES main.c) + +add_executable(${PROJECT_NAME}.elf ${SOURCES}) +set_target_properties(${PROJECT_NAME}.elf PROPERTIES + OUTPUT_NAME "${PROJECT_NAME}.elf" +) + +add_custom_command( + TARGET ${PROJECT_NAME}.elf POST_BUILD + COMMAND avr-objcopy -O ihex -R .eeprom ${PROJECT_NAME}.elf ${PROJECT_NAME}.hex + COMMENT "Converting ELF to Intel HEX" +) + +add_custom_target( + flash ALL + COMMAND avrdude -c ${AVRDUDE_PROGRAMMER} -p ${MCU} -P ${AVRDUDE_PORT} -b ${AVRDUDE_BAUDRATE} -U flash:w:${PROJECT_NAME}.hex:i + DEPENDS ${PROJECT_NAME}.elf + COMMENT "Flashing ${PROJECT_NAME}.hex to ${MCU}" +) + +# --- Fuse Setting Target (make fuses) --- +# NOTE: Set fuses to use the 8MHz internal oscillator. +# ATtiny45 default is 8MHz, but divided by 8 (1MHz). This sets the CKDIV8 fuse to be UNPROGRAMMED. +# Low Fuse (L): 0xE2 (Internal 8MHz Oscillator, Start-up time 6 CK + 65ms, **CKDIV8 disabled**) +# High Fuse (H): 0xDF (Default, Brown-out detection enabled) +# Extended Fuse (E): 0xFF (Default, Self-programming disabled) +add_custom_target( + fuses + COMMAND avrdude -c ${AVRDUDE_PROGRAMMER} -p ${MCU} -P ${AVRDUDE_PORT} -b ${AVRDUDE_BAUDRATE} -U lfuse:w:0xE2:m -U hfuse:w:0xDF:m -U efuse:w:0xFF:m + COMMENT "Setting fuses for 8MHz internal clock (L: 0xE2, H: 0xDF, E: 0xFF)" +) diff --git a/recv/pixmod_recv_1v0/main.c b/recv/pixmod_recv_1v0/main.c new file mode 100644 index 0000000..e2982b0 --- /dev/null +++ b/recv/pixmod_recv_1v0/main.c @@ -0,0 +1,277 @@ +#include //int +#include +#include +#include //int +#include //int +#include + +#define SERIAL_OUT true + +#define NEOPIXEL_PIN PB3 +#define NEOPIXEL_PORT PORTB +#define NEOPIXEL_DDR DDRB + +#define PULSE_IN_PIN PB4 +#define PULSE_IN_PORT PORTB +#define PULSE_IN_DDR DDRB +#define PULSE_IN_PIN_REG PINB + +#define UART_TX_PORT PORTB +#define UART_TX_DDR DDRB +#define UART_TX_PIN PB0 + +#define F_CPU 8000000UL +#define NUMPIXELS 2 +#define UART_BAUD 9600 +#define UART_BIT_DELAY_US (1000000UL / UART_BAUD) + + + +typedef struct { + uint8_t g; + uint8_t r; + uint8_t b; +} RGBColor; + +RGBColor pixels[NUMPIXELS]; + +// !time carefully for 800kHz (1.25us cycle) on 8MHz F_CPU +void ws2812_send() { + uint8_t *ptr = (uint8_t *)pixels; + uint16_t count = NUMPIXELS * 3; + uint8_t mask = _BV(NEOPIXEL_PIN); + uint8_t cli_mask = ~mask; + + NEOPIXEL_DDR |= mask; //set to output + + uint8_t sreg = SREG; + cli(); // disable interrupts + + NEOPIXEL_PORT &= cli_mask; + __asm__ __volatile__ ( + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + ); + + while (count--) { + uint8_t data = *ptr++; + + for (uint8_t i = 8; i--; ) { + if (data & 0x01) { + /*__asm__ __volatile__ ( + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + );*/ + NEOPIXEL_PORT |= mask; + __asm__ __volatile__ ( + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + + ); + NEOPIXEL_PORT &= cli_mask; + } else { + NEOPIXEL_PORT |= mask; + __asm__ __volatile__ ( + "nop\n\t" "nop\n\t" + ); + NEOPIXEL_PORT &= cli_mask; + } + + data <<= 1; + __asm__ __volatile__ ( + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" + ); + } + } + + SREG = sreg; + sei(); // enable interrupts +} + +void setPixelColor(uint8_t n, uint8_t r, uint8_t g, uint8_t b) { + if (n < NUMPIXELS) { + pixels[n].r = r; + pixels[n].g = g; + pixels[n].b = b; + } +} + + + +int uart_putchar(char c, FILE *stream); + +void uart_init(void) { + UART_TX_DDR |= (1 << UART_TX_PIN); // set to output + + UART_TX_PORT |= (1 << UART_TX_PIN); // set to HIGH - idle state in UART + + fdevopen(uart_putchar, NULL); +} + +void uart_transmit(uint8_t data) { + uint8_t i; + + UART_TX_PORT &= ~(1 << UART_TX_PIN); // LOW for start bit + _delay_us(UART_BIT_DELAY_US); + + // send 8 bits LSB + for (i = 0; i < 8; i++) { + if (data & (1 << i)) { + UART_TX_PORT |= (1 << UART_TX_PIN); // set high + } else { + UART_TX_PORT &= ~(1 << UART_TX_PIN); // set low + } + + _delay_us(UART_BIT_DELAY_US); + } + + UART_TX_PORT |= (1 << UART_TX_PIN); // high for stop bit + _delay_us(UART_BIT_DELAY_US); +} + +void uart_print_str(const char* str) { + while (*str) { + uart_transmit(*str++); + } +} + +int uart_putchar(char c, FILE *stream) { + uint8_t sreg = SREG; + cli(); + + if (c == '\n') { + uart_transmit('\r'); + } + uart_transmit(c); + + SREG = sreg; + sei(); + + return 0; +} + + + +uint16_t tim1_ic_val = 0; +char tim1_ic_flag = 0; + +uint16_t read_chained_timer(void) { + uint8_t sreg = SREG; + cli(); + + uint8_t high_byte = TCNT0; + uint8_t low_byte = TCNT1; + + SREG = sreg; + sei(); + + return ((uint16_t)high_byte << 8) | low_byte; +} + +ISR(TIMER1_OVF_vect) { + TCNT0++; +} + +ISR(PCINT0_vect) { + if(!(PINB & (1 << PULSE_IN_PIN))){ // pulsein pin is low + TCNT0 = 0x00; // reset tim0 + TCNT1 = 0x00; // reset tim1 + }else{ // pulsein pin is high + tim1_ic_val = read_chained_timer(); + tim1_ic_flag = 1; + //GIFR |= (1 << PCIF); // Clear the PCINT Flag (PCIF) after processing the interrupt + } +} + + + +int main() { + int d = 0; + int code = 0; + + DDRB &= ~(1 << PULSE_IN_PIN); // set to input + // PORTB |= (1 << PULSE_IN_PIN); // enable pullup + PCMSK |= (1 << PCINT4); // enable pin change interrupt 4 + GIMSK |= (1 << PCIE); // enable pin change interrupts + + //TCCR1B |= (1 << CS10); // clk/1 prescaler + TCNT1 = 0x00; // reset tim1 + TCCR1 &= ~((1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10)); // clear prescalers - stop tim1 + TCCR1 |= (1 << CS12); // CS12 high for clk/8 prescaler + //TCCR1 |= (1 << CS11) | (1 << CS10); + TIMSK |= (1 << TOIE1); // enable tim1 overflow int + + TCCR0B = 0x00; // clear prescalers to stop tim0 + TCNT0 = 0x00; + + sei(); // enable int + + + //if(SERIAL_OUT){ + uart_init(); + _delay_ms(500); + //}else{ + // Initialize I/O: Set the NeoPixel pin as an output + DDRB |= (1 << NEOPIXEL_PIN); + //} + + + + //if(SERIAL_OUT){ + printf("starting..\n"); + //}else{ + //setPixelColor(0, 0, 255, 0); + ws2812_send(); + //} + + while(1){ + if(tim1_ic_flag){ + //if(SERIAL_OUT){ + //printf("%d\n", (int)tim1_ic_val); + //} + + if(tim1_ic_val >= 400){ + if(tim1_ic_val > 2000){ + //if(SERIAL_OUT){ + printf(" %d\n", code); + //} + + if(code == 7774){ + //if(SERIAL_OUT){ + printf("+\n"); + //}else{ + setPixelColor(1, 0, 255, 0); + ws2812_send(); + //} + }else if(code == 15964){ + //if(SERIAL_OUT){ + printf("-\n"); + //}else{ + setPixelColor(1, 255, 0, 0); + ws2812_send(); + //} + } + + code = 0; + }else if(tim1_ic_val > 605){ + //if(SERIAL_OUT){ + printf("1"); + //} + ++code; + }else{ + //if(SERIAL_OUT){ + printf("0"); + //} + } + code *=2; + } + + tim1_ic_flag = 0; + } + _delay_us(10); + } + + return 0; +}