diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000..0c3c2619990d1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "array": "c", + "string": "c", + "string_view": "c" + } +} \ No newline at end of file diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 9f1d4ee9a0384..14f371a40e5d3 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -33,7 +33,7 @@ #include "i2c.h" #include "accel.h" -#if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 +#if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 || MICROPY_HW_HAS_LIS2DH12TR /// \moduleref pyb /// \class Accel - accelerometer control @@ -79,10 +79,62 @@ #define ACCEL_REG_DATA_CTRL_REG (0x21) #define ACCEL_AXIS_SIGNED_VALUE(i) (((i) & 0x7f) | ((i) & 0x80 ? (~0x7f) : 0)) +#elif MICROPY_HW_HAS_LIS2DH12TR + +#define ACCEL_ADDR (0x19) +#define ACCEL_ADDR_SUB (0x80) +#define ACCEL_REG_STATUS_REG_AUX (0x07) +#define ACCEL_REG_OUT_TEMP_L (0x0C) +#define ACCEL_REG_OUT_TEMP_H (0x0D) +#define ACCEL_REG_WHO_AM_I (0x0f) + +#define ACCEL_REG_CTRL_REG0 (0x1E) +#define ACCEL_REG_TEMP_CFG_REG (0x1F) +#define ACCEL_REG_CTRL_REG1 (0x20) +#define ACCEL_REG_CTRL_REG2 (0x21) +#define ACCEL_REG_CTRL_REG3 (0x22) +#define ACCEL_REG_CTRL_REG4 (0x23) +#define ACCEL_REG_CTRL_REG5 (0x24) +#define ACCEL_REG_CTRL_REG6 (0x25) +#define ACCEL_REG_REFERENCE (0x26) + +#define ACCEL_REG_STATUS_REG (0x27) + +#define ACCEL_REG_X (0x28) // XOUT_L +#define ACCEL_REG_Y (0x2A) // YOUT_L +#define ACCEL_REG_Z (0x2C) // ZOUT_L + +#define ACCEL_REG_FIFO_CTRL_REG (0x2E) +#define ACCEL_REG_FIFO_SRC_REG (0x2F) + +#define ACCEL_REG_INT1_CFG (0x30) +#define ACCEL_REG_INT1_SRC (0x31) +#define ACCEL_REG_INT1_THS (0x32) +#define ACCEL_REG_INT1_DURATION (0x33) + +#define ACCEL_REG_INT2_CFG (0x34) +#define ACCEL_REG_INT2_SRC (0x35) +#define ACCEL_REG_INT2_THS (0x36) +#define ACCEL_REG_INT2_DURATION (0x37) + +#define ACCEL_REG_CLICK_CFG (0x38) +#define ACCEL_REG_CLICK_SRC (0x39) +#define ACCEL_REG_CLICK_THS (0x3A) + +#define ACCEL_REG_TIME_LIMIT (0x3B) +#define ACCEL_REG_TIME_LATENCY (0x3C) +#define ACCEL_REG_TIME_WINDOW (0x3D) + +#define ACCEL_REG_ACT_THS (0x3E) +#define ACCEL_REG_ACT_DUR (0x3F) + + +#define ACCEL_AXIS_SIGNED_VALUE(lsb) (lsb>>4)*1//±2g + #endif void accel_init(void) { - #if MICROPY_HW_HAS_MMA7660 + #if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_LIS2DH12TR // PB5 is connected to AVDD; pull high to enable MMA accel device mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN); @@ -139,6 +191,38 @@ static void accel_start(void) { data[1] = 0x04; i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); + #elif MICROPY_HW_HAS_LIS2DH12TR + // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off + mp_hal_delay_ms(30); + mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on + mp_hal_delay_ms(30); + + int ret; + for (int i = 0; i < 4; i++) { + ret = i2c_writeto(I2C1, ACCEL_ADDR, NULL, 0, true); + if (ret == 0) { + break; + } + } + if (ret != 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("accelerometer not found")); + } + + uint8_t data[2] = { ACCEL_REG_WHO_AM_I }; + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); + if (data[0] != 0x33) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("accelerometer is not LIS2DH12TR")); + } + data[0] = ACCEL_REG_CTRL_REG1; + data[1] = 0x17;//1Hz,xyz enable + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); + + data[0] = ACCEL_REG_CTRL_REG4; + data[1] = 0x08;//BDU enable,±2g,12bit + i2c_writeto(I2C1, ACCEL_ADDR, data, 2, true); + #endif } @@ -178,10 +262,31 @@ static mp_obj_t pyb_accel_make_new(const mp_obj_type_t *type, size_t n_args, siz } static mp_obj_t read_axis(int axis) { + + #if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 + uint8_t data[1] = { axis }; i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); return mp_obj_new_int(ACCEL_AXIS_SIGNED_VALUE(data[0])); + + #elif MICROPY_HW_HAS_LIS2DH12TR + + uint8_t data[2] = { ACCEL_REG_STATUS_REG }; + do + { + data[0] = ACCEL_REG_STATUS_REG; + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); + } while (!(data[0]&0x80)); + data[0] = axis|ACCEL_ADDR_SUB;//set SUB + i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); + i2c_readfrom(I2C1, ACCEL_ADDR, data, 2, true); + int16_t acc = data[1]; + acc = (acc<<8)|data[0]; + return mp_obj_new_int(ACCEL_AXIS_SIGNED_VALUE(acc)); + + #endif } /// \method x() @@ -213,7 +318,7 @@ static mp_obj_t pyb_accel_tilt(mp_obj_t self_in) { i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); i2c_readfrom(I2C1, ACCEL_ADDR, data, 1, true); return mp_obj_new_int(data[0]); - #elif MICROPY_HW_HAS_KXTJ3 + #elif MICROPY_HW_HAS_KXTJ3 || MICROPY_HW_HAS_LIS2DH12TR /// No tilt like register with KXTJ3 accelerometer return 0; #endif @@ -224,7 +329,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt); /// Get a 3-tuple of filtered x, y and z values. static mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { pyb_accel_obj_t *self = MP_OBJ_TO_PTR(self_in); - +loop: memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t)); #if MICROPY_HW_HAS_MMA7660 @@ -233,20 +338,37 @@ static mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { #elif MICROPY_HW_HAS_KXTJ3 const size_t DATA_SIZE = 5; const size_t DATA_STRIDE = 2; + #elif MICROPY_HW_HAS_LIS2DH12TR + const size_t DATA_SIZE = 6; + const size_t DATA_STRIDE = 2; #endif uint8_t data[DATA_SIZE]; data[0] = ACCEL_REG_X; + #if MICROPY_HW_HAS_LIS2DH12TR + data[0] = ACCEL_REG_X|ACCEL_ADDR_SUB; + #endif i2c_writeto(I2C1, ACCEL_ADDR, data, 1, false); i2c_readfrom(I2C1, ACCEL_ADDR, data, DATA_SIZE, true); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { + #if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = ACCEL_AXIS_SIGNED_VALUE(data[i * DATA_STRIDE]); + #elif MICROPY_HW_HAS_LIS2DH12TR + int16_t acc = data[i * DATA_STRIDE+1]; + acc = (acc<<8)|data[i * DATA_STRIDE]; + self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = ACCEL_AXIS_SIGNED_VALUE(acc);//9 10 11 = x y z + #endif + int32_t val = 0; for (int j = 0; j < FILT_DEPTH; j++) { val += self->buf[i + NUM_AXIS * j]; } - tuple[i] = mp_obj_new_int(val); + tuple[i] = mp_obj_new_int(val/FILT_DEPTH); + } + if(self->buf[ 0]==0&&self->buf[1]==0&&self->buf[2]==0) + { + goto loop; } return mp_obj_new_tuple(3, tuple); diff --git a/ports/stm32/boards/MPY_v11/board.json b/ports/stm32/boards/MPY_v11/board.json new file mode 100644 index 0000000000000..6e3b7e4f8528d --- /dev/null +++ b/ports/stm32/boards/MPY_v11/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "MPYB_v11.jpg" + ], + "mcu": "stm32f4", + "product": "MPY v1.1", + "thumbnail": "", + "url": "", + "variants": { + "DP": "Double-precision float", + "DP_THREAD": "Double precision float + Threads", + "NETWORK": "Wiznet 5200 Driver", + "THREAD": "Threading" + }, + "vendor": "NONE" +} diff --git a/ports/stm32/boards/MPY_v11/board.md b/ports/stm32/boards/MPY_v11/board.md new file mode 100644 index 0000000000000..b490d54046915 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/board.md @@ -0,0 +1 @@ +The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard. diff --git a/ports/stm32/boards/MPY_v11/mpconfigboard.h b/ports/stm32/boards/MPY_v11/mpconfigboard.h new file mode 100644 index 0000000000000..a43557be1e2c6 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigboard.h @@ -0,0 +1,111 @@ +#define MICROPY_HW_BOARD_NAME "PYBv1.1" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_LIS2DH12TR (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The pyboard has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C buses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI buses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// I2S buses +#define MICROPY_HW_I2S2 (1) + +// CAN buses +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_B3) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The pyboard has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_B5) + +// Bootloader configuration (only needed if Mboot is used) +#define MBOOT_I2C_PERIPH_ID 1 +#define MBOOT_I2C_SCL (pin_B8) +#define MBOOT_I2C_SDA (pin_B9) +#define MBOOT_I2C_ALTFUNC (4) diff --git a/ports/stm32/boards/MPY_v11/mpconfigboard.mk b/ports/stm32/boards/MPY_v11/mpconfigboard.mk new file mode 100644 index 0000000000000..89e4a1d8a4d2a --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigboard.mk @@ -0,0 +1,19 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 +endif + +# MicroPython settings +MICROPY_VFS_LFS2 = 1 + +# PYB-specific frozen modules +FROZEN_MANIFEST ?= boards/PYBV10/manifest.py diff --git a/ports/stm32/boards/MPY_v11/mpconfigvariant_DP.mk b/ports/stm32/boards/MPY_v11/mpconfigvariant_DP.mk new file mode 100644 index 0000000000000..73b32b4901dbf --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigvariant_DP.mk @@ -0,0 +1 @@ +MICROPY_FLOAT_IMPL = double diff --git a/ports/stm32/boards/MPY_v11/mpconfigvariant_DP_THREAD.mk b/ports/stm32/boards/MPY_v11/mpconfigvariant_DP_THREAD.mk new file mode 100644 index 0000000000000..af6ec87ecfc12 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigvariant_DP_THREAD.mk @@ -0,0 +1,2 @@ +MICROPY_FLOAT_IMPL = double +CFLAGS += -DMICROPY_PY_THREAD=1 diff --git a/ports/stm32/boards/MPY_v11/mpconfigvariant_NETWORK.mk b/ports/stm32/boards/MPY_v11/mpconfigvariant_NETWORK.mk new file mode 100644 index 0000000000000..2e2988aa93056 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigvariant_NETWORK.mk @@ -0,0 +1 @@ +MICROPY_PY_NETWORK_WIZNET5K = 5200 diff --git a/ports/stm32/boards/MPY_v11/mpconfigvariant_THREAD.mk b/ports/stm32/boards/MPY_v11/mpconfigvariant_THREAD.mk new file mode 100644 index 0000000000000..eab5c1c0d2333 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/mpconfigvariant_THREAD.mk @@ -0,0 +1 @@ +CFLAGS += -DMICROPY_PY_THREAD=1 diff --git a/ports/stm32/boards/MPY_v11/pins.csv b/ports/stm32/boards/MPY_v11/pins.csv new file mode 100644 index 0000000000000..dc3e48f138595 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/pins.csv @@ -0,0 +1,59 @@ +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +#X13,Reset +#X14,GND +#X15,3.3V +#X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +#X23,A3.3V +#X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB8 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y12,PB1 +#Y13,Reset +#Y14,GND +#Y15,3.3V +#Y16,VIN +SW,PB3 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +LED_BLUE,PB4 +MMA_INT,PB2 +MMA_AVDD,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD,PA8 +SD_SW,PA8 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/MPY_v11/stm32f4xx_hal_conf.h b/ports/stm32/boards/MPY_v11/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000000..21285f2e33602 --- /dev/null +++ b/ports/stm32/boards/MPY_v11/stm32f4xx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H + +// Oscillator values in Hz +#define HSE_VALUE (12000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#include "boards/stm32f4xx_hal_conf_base.h" + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 176010a7e5107..51fdc191af90e 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -253,7 +253,7 @@ static const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, #endif - #if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 + #if MICROPY_HW_HAS_MMA7660 || MICROPY_HW_HAS_KXTJ3 || MICROPY_HW_HAS_LIS2DH12TR { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) }, #endif pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy