// Platform-dependent functions #include "platform.h" #include "c_stdio.h" #include "c_string.h" #include "c_stdlib.h" #include "gpio.h" #include "user_interface.h" #include "driver/uart.h" // Platform specific includes static void pwms_init(); int platform_init() { // Setup PWMs pwms_init(); cmn_platform_init(); // All done return PLATFORM_OK; } // **************************************************************************** // KEY_LED functions uint8_t platform_key_led( uint8_t level){ uint8_t temp; gpio16_output_set(1); // set to high first, for reading key low level gpio16_input_conf(); temp = gpio16_input_get(); gpio16_output_conf(); gpio16_output_set(level); return temp; } // **************************************************************************** // GPIO functions #ifdef GPIO_INTERRUPT_ENABLE extern void lua_gpio_unref(unsigned pin); #endif int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull ) { // NODE_DBG("Function platform_gpio_mode() is called. pin_mux:%d, func:%d\n",pin_mux[pin],pin_func[pin]); if (pin >= NUM_GPIO) return -1; if(pin == 0){ if(mode==PLATFORM_GPIO_INPUT) gpio16_input_conf(); else gpio16_output_conf(); return 1; } platform_pwm_close(pin); // closed from pwm module, if it is used in pwm switch(pull){ case PLATFORM_GPIO_PULLUP: PIN_PULLDWN_DIS(pin_mux[pin]); PIN_PULLUP_EN(pin_mux[pin]); break; case PLATFORM_GPIO_PULLDOWN: PIN_PULLUP_DIS(pin_mux[pin]); PIN_PULLDWN_EN(pin_mux[pin]); break; case PLATFORM_GPIO_FLOAT: PIN_PULLUP_DIS(pin_mux[pin]); PIN_PULLDWN_DIS(pin_mux[pin]); break; default: PIN_PULLUP_DIS(pin_mux[pin]); PIN_PULLDWN_DIS(pin_mux[pin]); break; } switch(mode){ case PLATFORM_GPIO_INPUT: #ifdef GPIO_INTERRUPT_ENABLE lua_gpio_unref(pin); // unref the lua ref call back. #endif GPIO_DIS_OUTPUT(pin_num[pin]); case PLATFORM_GPIO_OUTPUT: ETS_GPIO_INTR_DISABLE(); #ifdef GPIO_INTERRUPT_ENABLE pin_int_type[pin] = GPIO_PIN_INTR_DISABLE; #endif PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]); //disable interrupt gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_DISABLE); //clear interrupt status GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin])); GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain; ETS_GPIO_INTR_ENABLE(); break; #ifdef GPIO_INTERRUPT_ENABLE case PLATFORM_GPIO_INT: ETS_GPIO_INTR_DISABLE(); PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]); GPIO_DIS_OUTPUT(pin_num[pin]); gpio_register_set(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE)); ETS_GPIO_INTR_ENABLE(); break; #endif default: break; } return 1; } int platform_gpio_write( unsigned pin, unsigned level ) { // NODE_DBG("Function platform_gpio_write() is called. pin:%d, level:%d\n",GPIO_ID_PIN(pin_num[pin]),level); if (pin >= NUM_GPIO) return -1; if(pin == 0){ gpio16_output_conf(); gpio16_output_set(level); return 1; } GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level); } int platform_gpio_read( unsigned pin ) { // NODE_DBG("Function platform_gpio_read() is called. pin:%d\n",GPIO_ID_PIN(pin_num[pin])); if (pin >= NUM_GPIO) return -1; if(pin == 0){ // gpio16_input_conf(); return 0x1 & gpio16_input_get(); } // GPIO_DIS_OUTPUT(pin_num[pin]); return 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin])); } #ifdef GPIO_INTERRUPT_ENABLE static void platform_gpio_intr_dispatcher( platform_gpio_intr_handler_fn_t cb){ uint8 i, level; uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); for (i = 0; i < GPIO_PIN_NUM; i++) { if (pin_int_type[i] && (gpio_status & BIT(pin_num[i])) ) { //disable interrupt gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), GPIO_PIN_INTR_DISABLE); //clear interrupt status GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(pin_num[i])); level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[i])); if(cb){ cb(i, level); } gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), pin_int_type[i]); } } } void platform_gpio_init( platform_gpio_intr_handler_fn_t cb ) { ETS_GPIO_INTR_ATTACH(platform_gpio_intr_dispatcher, cb); } int platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type ) { if (pin >= NUM_GPIO) return -1; ETS_GPIO_INTR_DISABLE(); //clear interrupt status GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin])); pin_int_type[pin] = type; //enable interrupt gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type); ETS_GPIO_INTR_ENABLE(); } #endif // **************************************************************************** // UART // TODO: Support timeouts. // UartDev is defined and initialized in rom code. extern UartDevice UartDev; uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits ) { switch( baud ) { case BIT_RATE_300: case BIT_RATE_600: case BIT_RATE_1200: case BIT_RATE_2400: case BIT_RATE_4800: case BIT_RATE_9600: case BIT_RATE_19200: case BIT_RATE_38400: case BIT_RATE_57600: case BIT_RATE_74880: case BIT_RATE_115200: case BIT_RATE_230400: case BIT_RATE_256000: case BIT_RATE_460800: case BIT_RATE_921600: case BIT_RATE_1843200: case BIT_RATE_3686400: UartDev.baut_rate = baud; break; default: UartDev.baut_rate = BIT_RATE_9600; break; } switch( databits ) { case 5: UartDev.data_bits = FIVE_BITS; break; case 6: UartDev.data_bits = SIX_BITS; break; case 7: UartDev.data_bits = SEVEN_BITS; break; case 8: UartDev.data_bits = EIGHT_BITS; break; default: UartDev.data_bits = EIGHT_BITS; break; } switch (stopbits) { case PLATFORM_UART_STOPBITS_1: UartDev.stop_bits = ONE_STOP_BIT; break; case PLATFORM_UART_STOPBITS_2: UartDev.stop_bits = TWO_STOP_BIT; break; default: UartDev.stop_bits = ONE_STOP_BIT; break; } switch (parity) { case PLATFORM_UART_PARITY_EVEN: UartDev.parity = EVEN_BITS; break; case PLATFORM_UART_PARITY_ODD: UartDev.parity = ODD_BITS; break; default: UartDev.parity = NONE_BITS; break; } uart_setup(id); return baud; } // Send: version with and without mux void platform_uart_send( unsigned id, u8 data ) { uart_tx_one_char(id, data); } // **************************************************************************** // PWMs static uint16_t pwms_duty[NUM_PWM] = {0}; static void pwms_init() { int i; for(i=0;i= NUM_PWM) return 0; if(!pwm_exist(pin)) return 0; return (uint32_t)pwm_get_freq(pin); } // Set the PWM clock uint32_t platform_pwm_set_clock( unsigned pin, uint32_t clock ) { // NODE_DBG("Function platform_pwm_set_clock() is called.\n"); if( pin >= NUM_PWM) return 0; if(!pwm_exist(pin)) return 0; pwm_set_freq((uint16_t)clock, pin); pwm_start(); return (uint32_t)pwm_get_freq( pin ); } uint32_t platform_pwm_get_duty( unsigned pin ) { // NODE_DBG("Function platform_pwm_get_duty() is called.\n"); if( pin < NUM_PWM){ if(!pwm_exist(pin)) return 0; // return NORMAL_DUTY(pwm_get_duty(pin)); return pwms_duty[pin]; } return 0; } // Set the PWM duty uint32_t platform_pwm_set_duty( unsigned pin, uint32_t duty ) { // NODE_DBG("Function platform_pwm_set_duty() is called.\n"); if ( pin < NUM_PWM) { if(!pwm_exist(pin)) return 0; pwm_set_duty(DUTY(duty), pin); } else { return 0; } pwm_start(); pwms_duty[pin] = NORMAL_DUTY(pwm_get_duty(pin)); return pwms_duty[pin]; } uint32_t platform_pwm_setup( unsigned pin, uint32_t frequency, unsigned duty ) { uint32_t clock; if ( pin < NUM_PWM) { platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); // disable gpio interrupt first if(!pwm_add(pin)) return 0; // pwm_set_duty(DUTY(duty), pin); pwm_set_duty(0, pin); pwms_duty[pin] = duty; pwm_set_freq((uint16_t)frequency, pin); } else { return 0; } clock = platform_pwm_get_clock( pin ); pwm_start(); return clock; } void platform_pwm_close( unsigned pin ) { // NODE_DBG("Function platform_pwm_stop() is called.\n"); if ( pin < NUM_PWM) { pwm_delete(pin); pwm_start(); } } void platform_pwm_start( unsigned pin ) { // NODE_DBG("Function platform_pwm_start() is called.\n"); if ( pin < NUM_PWM) { if(!pwm_exist(pin)) return; pwm_set_duty(DUTY(pwms_duty[pin]), pin); pwm_start(); } } void platform_pwm_stop( unsigned pin ) { // NODE_DBG("Function platform_pwm_stop() is called.\n"); if ( pin < NUM_PWM) { if(!pwm_exist(pin)) return; pwm_set_duty(0, pin); pwm_start(); } } // ***************************************************************************** // I2C platform interface uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed ){ if (sda >= NUM_GPIO || scl >= NUM_GPIO) return 0; // platform_pwm_close(sda); // platform_pwm_close(scl); // disable gpio interrupt first platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // inside this func call platform_pwm_close platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // disable gpio interrupt first i2c_master_gpio_init(sda, scl); return PLATFORM_I2C_SPEED_SLOW; } void platform_i2c_send_start( unsigned id ){ i2c_master_start(); } void platform_i2c_send_stop( unsigned id ){ i2c_master_stop(); } int platform_i2c_send_address( unsigned id, uint16_t address, int direction ){ // Convert enum codes to R/w bit value. // If TX == 0 and RX == 1, this test will be removed by the compiler if ( ! ( PLATFORM_I2C_DIRECTION_TRANSMITTER == 0 && PLATFORM_I2C_DIRECTION_RECEIVER == 1 ) ) { direction = ( direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ) ? 0 : 1; } i2c_master_writeByte( (uint8_t) ((address << 1) | direction )); // Low-level returns nack (0=acked); we return ack (1=acked). return ! i2c_master_getAck(); } int platform_i2c_send_byte( unsigned id, uint8_t data ){ i2c_master_writeByte(data); // Low-level returns nack (0=acked); we return ack (1=acked). return ! i2c_master_getAck(); } int platform_i2c_recv_byte( unsigned id, int ack ){ uint8_t r = i2c_master_readByte(); i2c_master_setAck( !ack ); return r; } // ***************************************************************************** // SPI platform interface uint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock_div) { spi_master_init(id, cpol, cpha, databits, clock_div); return 1; } spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data ) { spi_mast_byte_write(id, &data); return data; } // **************************************************************************** // Flash access functions /* * Assumptions: * > toaddr is INTERNAL_FLASH_WRITE_UNIT_SIZE aligned * > size is a multiple of INTERNAL_FLASH_WRITE_UNIT_SIZE */ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size ) { toaddr -= INTERNAL_FLASH_START_ADDRESS; SpiFlashOpResult r; const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1; uint32_t *apbuf = NULL; uint32_t fromaddr = (uint32_t)from; if( (fromaddr & blkmask ) || (fromaddr >= INTERNAL_FLASH_START_ADDRESS)) { apbuf = (uint32_t *)c_malloc(size); if(!apbuf) return 0; c_memcpy(apbuf, from, size); } WRITE_PERI_REG(0x60000914, 0x73); r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); if(apbuf) c_free(apbuf); if(SPI_FLASH_RESULT_OK == r) return size; else{ NODE_ERR( "ERROR in flash_write: r=%d at %08X\n", ( int )r, ( unsigned )toaddr+INTERNAL_FLASH_START_ADDRESS ); return 0; } } /* * Assumptions: * > fromaddr is INTERNAL_FLASH_READ_UNIT_SIZE aligned * > size is a multiple of INTERNAL_FLASH_READ_UNIT_SIZE */ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size ) { if (size==0) return 0; fromaddr -= INTERNAL_FLASH_START_ADDRESS; SpiFlashOpResult r; WRITE_PERI_REG(0x60000914, 0x73); const uint32_t blkmask = (INTERNAL_FLASH_READ_UNIT_SIZE - 1); if( ((uint32_t)to) & blkmask ) { uint32_t size2=size-INTERNAL_FLASH_READ_UNIT_SIZE; uint32* to2=(uint32*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE); r = flash_read(fromaddr, to2, size2); if(SPI_FLASH_RESULT_OK == r) { os_memmove(to,to2,size2); char back[ INTERNAL_FLASH_READ_UNIT_SIZE ] __attribute__ ((aligned(INTERNAL_FLASH_READ_UNIT_SIZE))); r=flash_read(fromaddr+size2,(uint32*)back,INTERNAL_FLASH_READ_UNIT_SIZE); os_memcpy((uint8_t*)to+size2,back,INTERNAL_FLASH_READ_UNIT_SIZE); } } else r = flash_read(fromaddr, (uint32 *)to, size); if(SPI_FLASH_RESULT_OK == r) return size; else{ NODE_ERR( "ERROR in flash_read: r=%d at %08X\n", ( int )r, ( unsigned )fromaddr+INTERNAL_FLASH_START_ADDRESS ); return 0; } } int platform_flash_erase_sector( uint32_t sector_id ) { WRITE_PERI_REG(0x60000914, 0x73); return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR; }