├── .gitignore ├── README.md ├── build.sh ├── clean.sh ├── cross-file.txt ├── libopencm3_f1.ld ├── main.cpp └── meson.build /.gitignore: -------------------------------------------------------------------------------- 1 | */build/ 2 | */build/* 3 | */builddir/ 4 | */builddir/* 5 | builddir/ 6 | build/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # i2c slave based on stm32 2 | This is an i2c slave based on stm32. This implements a simple math calculator 3 | for doing addition, subtraction and multiplication of given two numbers. 4 | 5 | ## How to compile 6 | 7 | Modify `meson.build` according to your needs. 8 | 9 | `libocm3Path` - libopencm3 directory path 10 | 11 | You need to issue `./build.sh` once. 12 | ```shell 13 | $ ./build.sh 14 | $ cd builddir 15 | ``` 16 | `ninja` - generates elf file. 17 | ```shell 18 | $ ninja 19 | ``` 20 | 21 | `ninja hex` - generates hex file. 22 | ```shell 23 | $ ninja hex 24 | ``` 25 | `ninja size` - gives the summary of hex file size. 26 | ```shell 27 | $ ninja size 28 | ``` 29 | `ninja upload` - upload hex file to stm32 via stlink programmer. 30 | ```shell 31 | $ ninja upload 32 | ``` 33 | 34 | Refer to [my blog](http://amitesh-singh.github.io/stm32/2018/01/07/making-i2c-slave-using-stm32f103.html) for more details. 35 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | meson . builddir --cross-file cross-file.txt --buildtype=minsize 2 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./builddir 2 | -------------------------------------------------------------------------------- /cross-file.txt: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'arm-none-eabi-gcc' 3 | cpp = 'arm-none-eabi-g++' 4 | ar = 'arm-none-eabi-ar' 5 | strip = 'arm-none-eabi-strip' 6 | objcopy = 'arm-none-eabi-objcopy' 7 | size = 'arm-none-eabi-size' 8 | 9 | [host_machine] 10 | system = 'linux' 11 | cpu_family = 'x86_64' 12 | cpu = 'x64' 13 | endian = 'little' 14 | 15 | [target_machine] 16 | system = 'bare-metel' 17 | cpu_family = 'arm' 18 | cpu = 'cortex-m3' 19 | endian = 'little' 20 | -------------------------------------------------------------------------------- /libopencm3_f1.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K 4 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 20K 5 | } 6 | 7 | INCLUDE cortex-m-generic.ld 8 | 9 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * math calculator i2c slave stm32 3 | * Copyright (C) 2018 Amitesh Singh 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | extern "C" 20 | { 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | } 27 | 28 | static void 29 | my_delay_1( void ) 30 | { 31 | int i = 72e6/2/4; 32 | 33 | while( i > 0 ) 34 | { 35 | i--; 36 | __asm__( "nop" ); 37 | } 38 | } 39 | 40 | #define MYSLAVE_ADDRESS 0x32 41 | //Set Commands 42 | #define MYSLAVE_SET_REG 0x01 43 | //GET commands 44 | #define MYSLAVE_GET_ADD_RESULT 0x02 45 | #define MYSLAVE_GET_SUB_RESULT 0x03 46 | #define MYSLAVE_GET_MUL_RESULT 0x04 47 | 48 | static void 49 | i2c_slave_init(uint8_t ownaddress) 50 | { 51 | rcc_periph_clock_enable(RCC_GPIOB); 52 | rcc_periph_clock_enable(RCC_I2C1); 53 | 54 | nvic_enable_irq(NVIC_I2C1_EV_IRQ); 55 | 56 | // configure i2c pins 57 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, 58 | GPIO_I2C1_SDA); //PB7 59 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, 60 | GPIO_I2C1_SCL); //PB6 61 | 62 | i2c_peripheral_disable(I2C1); 63 | 64 | i2c_set_speed(I2C1, i2c_speed_sm_100k, 36); 65 | i2c_set_own_7bit_slave_address(I2C1, ownaddress); 66 | i2c_enable_interrupt(I2C1, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); 67 | i2c_peripheral_enable(I2C1); 68 | 69 | // slave needs to acknowledge on receiving bytes 70 | // set it after enabling Peripheral i.e. PE = 1 71 | i2c_enable_ack(I2C1); 72 | } 73 | 74 | volatile uint8_t *read_p; 75 | volatile uint8_t *write_p; 76 | volatile uint8_t writing; 77 | volatile uint8_t reading; 78 | 79 | volatile uint8_t buf[3]; 80 | volatile uint16_t val; 81 | 82 | //i2c1 event ISR 83 | extern "C" void i2c1_ev_isr(void) 84 | { 85 | uint32_t sr1, sr2; 86 | 87 | sr1 = I2C_SR1(I2C1); 88 | 89 | // Address matched (Slave) 90 | if (sr1 & I2C_SR1_ADDR) 91 | { 92 | reading = 0; 93 | read_p = buf; 94 | write_p = ((volatile uint8_t *)(&val) + 1); 95 | writing = 2; 96 | //Clear the ADDR sequence by reading SR2. 97 | sr2 = I2C_SR2(I2C1); 98 | (void) sr2; 99 | } 100 | // Receive buffer not empty 101 | else if (sr1 & I2C_SR1_RxNE) 102 | { 103 | //ignore more than 3 bytes reading 104 | if (reading > 3) 105 | return; 106 | //read bytes from slave 107 | *read_p++ = i2c_get_data(I2C1); 108 | reading++; 109 | } 110 | // Transmit buffer empty & Data byte transfer not finished 111 | else if ((sr1 & I2C_SR1_TxE) && !(sr1 & I2C_SR1_BTF)) 112 | { 113 | //send data to master in MSB order 114 | i2c_send_data(I2C1, *write_p--); 115 | writing--; 116 | } 117 | // done by master by sending STOP 118 | //this event happens when slave is in Recv mode at the end of communication 119 | else if (sr1 & I2C_SR1_STOPF) 120 | { 121 | i2c_peripheral_enable(I2C1); 122 | 123 | if (buf[0] == MYSLAVE_GET_ADD_RESULT) 124 | val = buf[1] + buf[2]; 125 | else if (buf[0] == MYSLAVE_GET_SUB_RESULT) 126 | val = buf[1] - buf[2]; 127 | else if (buf[0] == MYSLAVE_GET_MUL_RESULT) 128 | val = buf[1] * buf[2]; 129 | } 130 | //this event happens when slave is in transmit mode at the end of communication 131 | else if (sr1 & I2C_SR1_AF) 132 | { 133 | //(void) I2C_SR1(I2C1); 134 | I2C_SR1(I2C1) &= ~(I2C_SR1_AF); 135 | } 136 | } 137 | 138 | int main( void ) 139 | { 140 | //set STM32 to 72 MHz 141 | rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); 142 | // Enable GPIOC clock 143 | rcc_periph_clock_enable(RCC_GPIOC); 144 | //Set GPIO13 (inbuild led connected) to 'output push-pull' 145 | gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, 146 | GPIO13); 147 | //switch led off 148 | gpio_set(GPIOC, GPIO13); 149 | 150 | //initialize i2c slave 151 | i2c_slave_init(MYSLAVE_ADDRESS); 152 | 153 | while( 1 ) 154 | { 155 | gpio_toggle(GPIOC, GPIO13); 156 | my_delay_1(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # stm32-libopencm3-meson build 3 | # Copyright (C) 2017 Amitesh Singh 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; 17 | # if not, see . 18 | # 19 | 20 | 21 | project('stm32f1-project', 'cpp') 22 | 23 | compiler_obj = meson.get_compiler('cpp') 24 | 25 | size = find_program('arm-none-eabi-size') 26 | objcopy = find_program('arm-none-eabi-objcopy') 27 | stinfo = find_program('st-info') 28 | stflash = find_program('st-flash') 29 | 30 | #define libopencm3 path here 31 | libocm3Path = '/home/ami/work/repos/libopencm3' 32 | 33 | #define cpu types here 34 | cputype = 'cortex-m3' 35 | cpudefine = 'STM32F1' 36 | libocm3cputype = 'opencm3_stm32f1' 37 | 38 | #Add your source files here 39 | srcfiles = ['main.cpp'] 40 | 41 | 42 | libocm3IncPath = libocm3Path + '/include' 43 | libocm3LibPath = libocm3Path + '/lib' 44 | libocm3LdPath = libocm3Path + '/lib/stm32/f1' 45 | 46 | # check for libopencm3 library 47 | libocm3lib_obj = compiler_obj.find_library(libocm3cputype, required: true, dirs: libocm3LibPath) 48 | if libocm3lib_obj.found() == true 49 | message('Found libopencm3 library at ' + libocm3Path) 50 | else 51 | error('unable to find libopencm3 library') 52 | endif 53 | 54 | incdir = include_directories(libocm3IncPath) 55 | 56 | stm32f1cargs = ['-Os', 57 | '-ggdb', 58 | '-mcpu=' + cputype, 59 | '-mthumb', 60 | '-msoft-float', 61 | '-std=gnu++14', 62 | '-Wall', 63 | '-Wshadow', 64 | '-ffunction-sections', 65 | '-fdata-sections', 66 | '-D' + cpudefine, 67 | '-fno-exceptions', 68 | #'-I' + libocm3IncPath 69 | ] 70 | 71 | stm32f1linkargs = ['-Os', 72 | '-ggdb', 73 | '-D' + cpudefine, 74 | '-fdata-sections', 75 | '-mcpu=' + cputype, 76 | '-mthumb', 77 | '-msoft-float', 78 | '-lc', 79 | '-flto', 80 | #'-T../libopencm3_f1.ld', 81 | '-T' + meson.current_source_dir() + '/libopencm3_f1.ld', 82 | '--specs=nosys.specs', 83 | '-nostartfiles', 84 | '-Wl,--gc-sections', 85 | '-L' + libocm3LibPath, 86 | '-L' + libocm3LdPath, 87 | # '-l' + libocm3cputype, 88 | ] 89 | 90 | p = ['blink', srcfiles, stm32f1cargs, stm32f1linkargs] 91 | 92 | exe = executable(p[0], p[1], 93 | cpp_args: p[2], 94 | link_args: p[3], 95 | include_directories : incdir, 96 | dependencies: libocm3lib_obj, 97 | build_by_default: true) 98 | 99 | run_target('hex', command: [objcopy, ['-Obinary', exe.full_path(), 100 | exe.full_path() + '.hex']], depends: exe) 101 | run_target('size', command: [size, exe.full_path(), '-B'], depends: exe) 102 | 103 | # STlink programmer related commands 104 | run_target('probe', command: [stinfo, '--probe']) 105 | run_target('upload', command: [stflash, 'write', exe.full_path() + '.hex', '0x08000000'], depends: exe) 106 | 107 | if meson.is_cross_build() 108 | message('cross compiling for ' + cputype) 109 | message(''' 110 | ninja - generates elf file. 111 | ninja hex - generates hex file. 112 | ninja upload - upload hex file to stm32 via stlink programmer. 113 | ninja probe - probe stlink programmer. 114 | ninja size - gives the summary of hex file size. 115 | (C) Amitesh Singh''') 116 | endif 117 | 118 | --------------------------------------------------------------------------------