Daniele Lacamera 3 years ago
commit
0c536ee600
9 changed files with 612 additions and 0 deletions
  1. 4 0
      .gdbinit
  2. 3 0
      .gitignore
  3. 3 0
      .gitmodules
  4. 43 0
      Makefile
  5. 15 0
      README.md
  6. 105 0
      libucmx_stm32l0.ld
  7. 429 0
      main.c
  8. 9 0
      openocd.conf
  9. 1 0
      unicore-mx

+ 4 - 0
.gdbinit

@@ -0,0 +1,4 @@
+tar rem:3333
+file image.elf
+foc c
+

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+*.o
+*.a
+tags

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "unicore-mx"]
+	path = unicore-mx
+	url = https://gitlab.com/insane-adding-machines/unicore-mx

+ 43 - 0
Makefile

@@ -0,0 +1,43 @@
+CROSS_COMPILE:=arm-none-eabi-
+CC:=$(CROSS_COMPILE)gcc
+LD:=$(CROSS_COMPILE)gcc
+VERSION?=1
+
+OBJS=main.o
+
+
+UMX:=unicore-mx/lib/libucmx_stm32l0.a
+UMXFLAGS:=-Iunicore-mx/include/ -DSTM32L0
+LIBS+=$(UMX)
+
+
+LSCRIPT:=unicore-mx/lib/stm32/l0/stm32l0xx6.ld
+
+OBJCOPY:=$(CROSS_COMPILE)objcopy
+
+CFLAGS:=-mcpu=cortex-m0 -mthumb -Wall -Wno-main -Wstack-usage=320 \
+   	-ffreestanding -Wno-unused -DBLOCK_SIZE=4096 -I. -Iunicore-mx/include \
+    -ffunction-sections -fdata-sections -DSTM32L0
+CFLAGS+=-specs=nano.specs -lc -lg 
+CFLAGS+=$(UMXFLAGS)
+CFLAGS+=-O3
+#CFLAGS+=-g -ggdb3
+
+ASFLAGS:=$(CFLAGS)
+
+LDFLAGS:=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -mcpu=cortex-m0 -mthumb -nostartfiles
+
+#all: image.bin
+
+image.bin: image.elf
+	$(OBJCOPY) -O binary $^ $@
+
+image.elf: $(LIBS) $(OBJS) $(LSCRIPT)
+	$(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
+
+$(UMX):
+	make -C unicore-mx FP_FLAGS="-O3 -mfloat-abi=soft" TARGETS=stm32/l0
+
+clean:
+	@rm -f image.bin image.elf *.o image.map
+	make -C unicore-mx clean

+ 15 - 0
README.md

@@ -0,0 +1,15 @@
+# README
+
+Clone 24LC64 flash from Nucleo-STM32L073.
+
+Pinout:
+ - SDA PC1 (Arduino A5) 
+ - SCL PC0 (Arduino A4)
+ - Red Led PA4 (Arduino A2)
+ - Green led PA5 (onboard)
+
+Source flash has I2C address 0x50 (0101000) and it's write-protected. (A0, A1, A2 = 0)
+Destination flash has I2C address 0x51 (0101001) (A0 = 1; A1, A2 = 0)
+
+
+

+ 105 - 0
libucmx_stm32l0.ld

@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using unicore-mx. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+	.text : {
+		*(.vectors)	/* Vector table */
+		*(.text*)	/* Program code */
+		. = ALIGN(4);
+		*(.rodata*)	/* Read-only data */
+		. = ALIGN(4);
+	} >rom
+
+	/* C++ Static constructors/destructors, also used for __attribute__
+	 * ((constructor)) and the likes */
+	.preinit_array : {
+		. = ALIGN(4);
+		__preinit_array_start = .;
+		KEEP (*(.preinit_array))
+		__preinit_array_end = .;
+	} >rom
+	.init_array : {
+		. = ALIGN(4);
+		__init_array_start = .;
+		KEEP (*(SORT(.init_array.*)))
+		KEEP (*(.init_array))
+		__init_array_end = .;
+	} >rom
+	.fini_array : {
+		. = ALIGN(4);
+		__fini_array_start = .;
+		KEEP (*(.fini_array))
+		KEEP (*(SORT(.fini_array.*)))
+		__fini_array_end = .;
+	} >rom
+
+	/*
+	 * Another section used by C++ stuff, appears when using newlib with
+	 * 64bit (long long) printf support
+	 */
+	.ARM.extab : {
+		*(.ARM.extab*)
+	} >rom
+	.ARM.exidx : {
+		__exidx_start = .;
+		*(.ARM.exidx*)
+		__exidx_end = .;
+	} >rom
+
+	. = ALIGN(4);
+	_etext = .;
+
+	.data : {
+		_data = .;
+		*(.data*)	/* Read-write initialized data */
+		. = ALIGN(4);
+		_edata = .;
+	} >ram AT >rom
+	_data_loadaddr = LOADADDR(.data);
+
+	.bss : {
+		_bss = .;
+		*(.bss*)	/* Read-write zero initialized data */
+		*(COMMON)
+		. = ALIGN(4);
+		_ebss = .;
+	} >ram
+
+	/*
+	 * The .eh_frame section appears to be used for C++ exception handling.
+	 * You may need to fix this if you're using C++.
+	 */
+	/DISCARD/ : { *(.eh_frame) }
+
+	. = ALIGN(4);
+	end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+

+ 429 - 0
main.c

@@ -0,0 +1,429 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unicore-mx/stm32/rcc.h>
+#include <unicore-mx/stm32/gpio.h>
+#include <string.h>
+#include <stdio.h>
+#define DMB() __asm__ volatile ("dmb")
+
+#define FLASH_BASE          (0x40022000)
+#define FLASH_ACR           (*(volatile uint32_t *)(FLASH_BASE + 0x00))
+
+#define LED_GREEN_PIN GPIO5
+#define LED_GREEN_PORT GPIOA
+
+#define LED_RED_PIN GPIO4
+#define LED_RED_PORT GPIOA
+
+#define I2C3_SDA_PIN GPIO1
+#define I2C3_SDA_PORT GPIOC
+#define I2C3_SCL_PIN GPIO0
+#define I2C3_SCL_PORT GPIOC
+#define I2C3_AF (7)
+
+#define I2C3_BASE 0x40007800
+#define I2C3 I2C3_BASE
+#define I2C I2C3
+
+
+#define I2C3_CR1        (*(volatile uint32_t *)(I2C3))
+#define I2C3_CR2        (*(volatile uint32_t *)(I2C3 + 0x04))
+#define I2C3_OAR1       (*(volatile uint32_t *)(I2C3 + 0x08))
+#define I2C3_OAR2       (*(volatile uint32_t *)(I2C3 + 0x0c))
+#define I2C3_TIMINGR    (*(volatile uint32_t *)(I2C3 + 0x10))
+#define I2C3_SR1        (*(volatile uint32_t *)(I2C3 + 0x14))
+#define I2C3_ISR        (*(volatile uint32_t *)(I2C3 + 0x18))
+#define I2C3_ICR        (*(volatile uint32_t *)(I2C3 + 0x1C))
+#define I2C3_TXDR       (*(volatile uint32_t *)(I2C3 + 0x28))
+#define I2C3_RXDR       (*(volatile uint32_t *)(I2C3 + 0x24))
+
+#define I2C_CR1_ENABLE               (1 << 0)
+#define I2C_CR1_DNF                  (1 << 8)
+#define I2C_CR1_ANFOFF               (1 << 12)
+#define I2C_CR1_NOSTRETCH            (1 << 17)
+
+#define I2C_CR2_START			     (1 << 13)
+#define I2C_CR2_STOP			     (1 << 14)
+#define I2C_CR2_RD_WRN			     (1 << 10)
+#define I2C_CR2_NBYTES_SHIFT         (16)
+#define I2C_CR2_RELOAD               (1 << 24)
+#define I2C_CR2_AUTOEND              (1 << 25)
+#define I2C_CR1_ACK			         (1 << 10)
+#define I2C_CR2_FREQ_MASK            (0x3ff)
+#define I2C_CCR_MASK                 (0xfff)
+
+#define I2C_ISR_TXIS                (1 << 1)
+#define I2C_ISR_TXE                 (1 << 0)
+#define I2C_ISR_RXNE                (1 << 2)
+#define I2C_ISR_NACKF               (1 << 4)
+#define I2C_ISR_TCR                 (1 << 7)
+
+#define I2C_ICR_ARLOCF              (1 << 9)
+#define I2C_ICR_BERRCF              (1 << 8)
+#define I2C_ICR_ADDRCF              (1 << 3)
+#define I2C_ICR_NACKF               (1 << 4)
+#define I2C_ICR_STOPF               (1 << 5)
+#define I2C_ICR_ALLCF (I2C_ICR_NACKF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ICR_ADDRCF )
+
+#define RCC_CFGR_PLLDIV2            (0x01 << 22)
+#define RCC_CFGR_PLLMUL4            (0x01 << 18)
+#define RCC_PRESCALER_DIV_NONE 0
+
+
+#define ROM_SRC 0x50
+#define ROM_DST 0x51
+#define ROM_TEST_NACK 0x52
+#define ROM_PAGE_SIZE (32)
+#define ROM_SIZE (8192)
+#define ROM_PAGES (ROM_SIZE / ROM_PAGE_SIZE)
+
+static void wait_a_bit(void)
+{
+    volatile int i;
+    for (i = 0; i < 30000; i++) {  /* Wait a bit. */
+        __asm__("nop");
+    }
+}
+
+static void i2c_acquire(void)
+{
+    rcc_periph_clock_enable(RCC_I2C3);
+    I2C3_CR1 |= I2C_CR1_ENABLE;
+}
+
+static void i2c_release(void)
+{
+    I2C3_CR1 &= ~(I2C_CR1_ENABLE);
+    rcc_periph_clock_disable(RCC_I2C3);
+}
+
+static void i2c_setup(void)
+{
+    /* 400KHz */
+    uint32_t presc = 0, scll = 0x2E, sclh = 0x11, sdadel = 0x01, scldel = 0x0b;
+    /* 100KHz */
+    //uint32_t presc = 1, scll = 0x56, sclh = 0x3e, sdadel = 0x01, scldel = 0x0a;
+    rcc_periph_clock_enable(RCC_GPIOC);
+    gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_HIGH, I2C3_SDA_PIN);
+    gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP,
+            I2C3_SDA_PIN | I2C3_SCL_PIN);
+    gpio_set_af(GPIOC, I2C3_AF, I2C3_SDA_PIN | I2C3_SCL_PIN);
+
+    i2c_acquire();
+
+    /* Disable */
+    I2C3_CR1 &= ~(I2C_CR1_ENABLE);
+
+    /* configure analog noise filter */
+    I2C3_CR1 |= I2C_CR1_ANFOFF;
+
+    /* configure digital noise filter */
+    I2C3_CR1 |= I2C_CR1_DNF;
+
+    /* set timing registers */
+    I2C3_TIMINGR = (presc << 28) | (scldel << 20) | (sdadel << 16) | (sclh << 8) | scll;
+
+    /* configure clock stretching */
+    I2C3_CR1 &= ~(I2C_CR1_NOSTRETCH);
+
+    /* Clear interrupt */
+    I2C3_ICR |= I2C_ICR_ALLCF;
+
+    i2c_release();
+
+}
+
+static void gpio_setup(void)
+{
+    /* Enable GPIO clock. */
+    rcc_periph_clock_enable(RCC_GPIOA);
+
+    /* set pins to output mode, push pull */
+    gpio_mode_setup(LED_GREEN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_GREEN_PIN);
+    gpio_mode_setup(LED_RED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_RED_PIN);
+}
+
+static void wait_sent(void)
+{
+    volatile uint32_t sr1;
+    do {
+        sr1 = I2C3_ISR;
+    } while ((sr1 & (I2C_ISR_TXE)) == 0);
+}
+
+static void wait_reload(void)
+{
+    volatile uint32_t sr1;
+    do {
+        sr1 = I2C3_ISR;
+    } while ((sr1 & (I2C_ISR_TCR)) == 0);
+}
+
+static void wait_start(void)
+{
+    volatile uint32_t cr2;
+    do {
+        cr2 = I2C3_CR2;
+    } while ((cr2 & (I2C_CR2_START)) != 0);
+}
+
+static void wait_stop(void)
+{
+    volatile uint32_t cr2;
+    do {
+        cr2 = I2C3_CR2;
+    } while ((cr2 & (I2C_CR2_STOP)) != 0);
+}
+
+static void wait_rxd(void)
+{
+    volatile uint32_t sr1;
+    do {
+        sr1 = I2C3_ISR;
+    } while ((sr1 & (I2C_ISR_RXNE)) == 0);
+}
+
+static void clear_err(void)
+{
+    I2C3_ICR |= I2C_ICR_ALLCF;
+}
+
+static void clear_stop(void)
+{
+    I2C3_ICR |= I2C_ICR_STOPF;
+}
+
+static int eeprom_write_page(uint8_t rom, uint16_t address, const uint8_t *buf)
+{
+    volatile uint32_t sr1, sr2, cr2;
+    int i;
+    if (rom != ROM_DST)
+        return 0;
+
+
+    clear_err();
+    I2C3_CR2 = ((ROM_PAGE_SIZE + 2) << I2C_CR2_NBYTES_SHIFT) | I2C_CR2_AUTOEND;
+    I2C3_CR2 |= (rom << 1);
+    I2C3_CR2 |= I2C_CR2_START;
+    wait_start();
+    I2C3_TXDR = ((uint8_t)((address >> 8) & (0xFF)));
+    wait_sent();
+    I2C3_TXDR = ((uint8_t)((address & 0xFF)));
+    for (i = 0; i < ROM_PAGE_SIZE; i++) {
+        wait_sent();
+        I2C3_TXDR = buf[i];
+    } 
+    wait_a_bit();
+    clear_stop();
+    return i;
+}
+
+static int eeprom_read_page(uint8_t rom, uint16_t address, uint8_t *buf)
+{
+    volatile uint32_t sr1, sr2;
+    int i;
+    clear_err();
+    I2C3_CR2 = (2 << I2C_CR2_NBYTES_SHIFT) | I2C_CR2_RELOAD;
+    I2C3_CR2 |= (rom << 1);
+    I2C3_CR2 |= I2C_CR2_START;
+    wait_start();
+    I2C3_TXDR = ((uint8_t)((address & 0xFF00) >> 8));
+    wait_sent();
+    clear_err();
+    I2C3_CR2 = (rom << 1);
+    I2C3_CR2 |= I2C_CR2_RD_WRN;
+    I2C3_CR2 |= (ROM_PAGE_SIZE << I2C_CR2_NBYTES_SHIFT);
+    I2C3_CR2 |= I2C_CR2_START;
+    I2C3_TXDR = ((uint8_t)((address & 0xFF)));
+    //wait_sent();
+    wait_start();
+    clear_err();
+
+    for (i = 0; i < ROM_PAGE_SIZE; i++) {
+        //I2C3_TXDR = 0xFF;
+        //wait_sent();
+        wait_rxd();
+        buf[i] = I2C3_RXDR;
+    }
+    I2C3_CR2 |= I2C_CR2_STOP;
+    clear_stop();
+    return i;
+}
+
+static int eeprom_read_cur(uint8_t rom, uint8_t *buf)
+{
+    int i;
+retry:
+    clear_err();
+    I2C3_CR2 = (ROM_PAGE_SIZE << I2C_CR2_NBYTES_SHIFT);
+    I2C3_CR2 |= (rom << 1) | I2C_CR2_RD_WRN;
+    I2C3_CR2 |= I2C_CR2_START;
+    wait_start();
+    if (I2C3_ISR & I2C_ISR_NACKF) {
+        wait_a_bit();
+        clear_stop();
+        goto retry;
+    }
+    for (i = 0; i < ROM_PAGE_SIZE; i++) {
+        wait_rxd();
+        buf[i] = I2C3_RXDR;
+    }
+    return i;
+}
+
+
+static void flash_set_waitstates(unsigned int waitstates)
+{
+    if (waitstates && ((FLASH_ACR & 1) == 0))
+        FLASH_ACR |=  1;
+    if (!waitstates && ((FLASH_ACR & 1) == 1))
+        FLASH_ACR &= 1;
+    while ((FLASH_ACR & 1) != waitstates)
+        ;
+}
+
+static void clock_pll_on(void)
+{
+    uint32_t reg32;
+    uint32_t cpu_freq, hsi_freq, hpre, ppre1, ppre2, flash_waitstates;
+
+    /* Enable Power controller */
+    rcc_periph_clock_enable(RCC_PWR);
+
+    /* Select clock parameters (CPU Speed = 32MHz) */
+    cpu_freq = 32000000;
+    hsi_freq = 16000000;
+    hpre  = RCC_PRESCALER_DIV_NONE;
+    ppre1 = RCC_PRESCALER_DIV_NONE;
+    ppre2 = RCC_PRESCALER_DIV_NONE;
+    flash_waitstates = 1;
+
+    flash_set_waitstates(flash_waitstates);
+
+    /* Enable internal high-speed oscillator. */
+    RCC_CR |= RCC_CR_HSI16ON;
+    DMB();
+    while ((RCC_CR & RCC_CR_HSI16RDY) == 0) {};
+
+    /* Select HSI as SYSCLK source. */
+    reg32 = RCC_CFGR;
+    reg32 &= ~((1 << 1) | (1 << 0));
+    RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI16);
+    DMB();
+
+    /*
+     * Set prescalers for AHB, ADC, ABP1, ABP2.
+     */
+    reg32 = RCC_CFGR;
+    reg32 &= ~(0xF << 4);
+    RCC_CFGR = (reg32 | (hpre << 4));
+    DMB();
+    reg32 = RCC_CFGR;
+    reg32 &= ~(0x07 << 8);
+    RCC_CFGR = (reg32 | (ppre1 << 8));
+    DMB();
+    reg32 &= ~(0x07 << 11);
+    RCC_CFGR = (reg32 | (ppre2 << 11));
+    DMB();
+    reg32 &= ~(0x0F << 18);
+    RCC_CFGR = (reg32 | RCC_CFGR_PLLMUL4);
+    DMB();
+    reg32 &= ~(0x03 << 22);
+    RCC_CFGR = (reg32 | RCC_CFGR_PLLDIV2);
+    DMB();
+    /* Enable PLL oscillator and wait for it to stabilize. */
+    RCC_CR |= RCC_CR_PLLON;
+    DMB();
+    while ((RCC_CR & RCC_CR_PLLRDY) == 0) {};
+
+    /* Select PLL as SYSCLK source. */
+    reg32 = RCC_CFGR;
+    reg32 &= ~((1 << 1) | (1 << 0));
+    RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL);
+    DMB();
+
+    /* Wait for PLL clock to be selected. */
+    while (((RCC_CFGR >> 2) & 0x03) != RCC_CFGR_SW_PLL)
+        ;
+}
+
+
+static uint8_t cache[ROM_PAGE_SIZE];
+static uint8_t vcache[ROM_PAGE_SIZE];
+
+int main(void)
+{
+    int i;
+    clock_pll_on();
+
+    gpio_setup();
+    gpio_set(LED_RED_PORT, LED_RED_PIN);
+    i2c_setup();
+    wait_a_bit();
+    wait_a_bit();
+    wait_a_bit();
+    i2c_acquire();
+
+
+#if 0
+    /* TEST - fill the DST */
+    for (i = 0; i < ROM_PAGES; i++) {
+        memset(cache, (uint8_t)i, 32);
+        eeprom_write_page(ROM_DST,i * ROM_PAGE_SIZE,cache);
+    }
+#endif
+    memset(cache, 0, 32);
+    for (i = 0; i < ROM_PAGES; i++) {
+        /* Green: Read */
+        gpio_set(LED_RED_PORT, LED_GREEN_PIN);
+        gpio_clear(LED_GREEN_PORT, LED_GREEN_PIN);
+        eeprom_read_page(ROM_SRC, i * ROM_PAGE_SIZE, cache);
+        eeprom_read_page(ROM_DST, i * ROM_PAGE_SIZE, vcache);
+        if(memcmp(vcache, cache, ROM_PAGE_SIZE) == 0) {
+            /* Skip sector, already matching. */
+            continue;
+        }
+        /* Red: Write */
+        gpio_set(LED_GREEN_PORT, LED_GREEN_PIN);
+        gpio_clear(LED_RED_PORT, LED_RED_PIN);
+        eeprom_write_page(ROM_DST, i * ROM_PAGE_SIZE, cache);
+
+        /* Both: verify */
+        gpio_clear(LED_GREEN_PORT, LED_GREEN_PIN);
+        eeprom_read_page(ROM_DST, i * ROM_PAGE_SIZE, vcache);
+        if(memcmp(vcache, cache, ROM_PAGE_SIZE) != 0) {
+            while(1) {
+                /* blink red: panic */
+                gpio_toggle(LED_RED_PORT, LED_RED_PIN);
+                for (i = 0; i < 10; i++)
+                    wait_a_bit();
+            }
+        }
+        gpio_set(LED_GREEN_PORT, LED_GREEN_PIN);
+        gpio_set(LED_RED_PORT, LED_RED_PIN);
+    }
+    i2c_release();
+
+    while (1) {
+        /* blink green: success */
+        gpio_set(LED_RED_PORT, LED_RED_PIN);
+        gpio_toggle(LED_GREEN_PORT, LED_GREEN_PIN);
+        for (i = 0; i < 10; i++)
+            wait_a_bit();
+    }
+
+    return 0;
+}

+ 9 - 0
openocd.conf

@@ -0,0 +1,9 @@
+source [find interface/stlink-v2-1.cfg]
+#source [find target/stm32l0.cfg]
+source [find target/stm32l0_dual_bank.cfg]
+$_TARGETNAME configure -event reset-init {
+    mmw 0xe0042004 0x7 0x0
+}
+init
+reset
+halt

+ 1 - 0
unicore-mx

@@ -0,0 +1 @@
+Subproject commit c1cd3fded697da9636c546007f9d49be8bf488fd