Это 2.5+МГц !
Код (ногодрыг через bit banding) крутится на STM32F103C8… 72МГц.
Program Size: Code=228 RO-data=1096 RW-data=0 ZI-data=0
для Keil
#include "stm32f103xb.h"
#include "core_cm3.h"
#include "stdint.h"
#define SDA_PORT GPIOA
#define SDA_PIN 0
#define SCL_PORT GPIOB
#define SCL_PIN 0
#define SSD1306_addr 0x3C
int __main (void) __attribute__ ((section ("InRoot$$Sections")));
void __reset (void);
extern uint32_t const __Vector_Table [];
uint32_t const __Vector_Table [] __attribute__ ((section ("RESET")))={
(uint32_t) &__Vector_Table [2], //Top of stack
(uint32_t) &__reset, //Reset handler
0x20005000,
PERIPH_BB_BASE+((uint32_t)&RCC->CR-PERIPH_BASE)*32+RCC_CR_HSION_Pos*4,
PERIPH_BB_BASE+((uint32_t)&FLASH->ACR-PERIPH_BASE)*32+POS(FLASH_ACR_LATENCY_1)*4,
(uint32_t)&RCC->CFGR,
RCC_CFGR_PLLMULL9|RCC_CFGR_PLLSRC|RCC_CFGR_PPRE1_DIV2,
PERIPH_BB_BASE+((uint32_t)&RCC->CFGR-PERIPH_BASE)*32+POS(RCC_CFGR_SW_1)*4,
(uint32_t)&SysTick->CTRL,
0xffffff,
SysTick_CTRL_CLKSOURCE_Msk+SysTick_CTRL_ENABLE_Msk
};
//!!! Global variables will not be initialized !!!
static const uint8_t init_bytes[]={SSD1306_addr<<1,0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8,
0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF};
static const uint8_t test[]={SSD1306_addr<<1,0x40,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static void i2c_init(void) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
if ((&SDA_PORT->CRL == &GPIOA->CRL) || (&SCL_PORT->CRL == &GPIOA->CRL)) *(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&RCC->APB2ENR-PERIPH_BASE)*32+POS(RCC_APB2ENR_IOPAEN)*4)=1;
if ((&SDA_PORT->CRL == &GPIOB->CRL) || (&SCL_PORT->CRL == &GPIOB->CRL)) *(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&RCC->APB2ENR-PERIPH_BASE)*32+POS(RCC_APB2ENR_IOPBEN)*4)=1;
#pragma clang diagnostic pop
}
static void i2c_start(void) {
*(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&SDA_PORT->CRL-PERIPH_BASE)*32+SDA_PIN*4*4)=1;
*(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&SCL_PORT->CRL-PERIPH_BASE)*32+SCL_PIN*4*4)=1;
}
static void i2c_stop(void) {
*(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&SDA_PORT->CRL-PERIPH_BASE)*32+SDA_PIN*4*4)=1;
*(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&SCL_PORT->CRL-PERIPH_BASE)*32+SCL_PIN*4*4)=0;
*(volatile uint32_t*)(PERIPH_BB_BASE+((uint32_t)&SDA_PORT->CRL-PERIPH_BASE)*32+SDA_PIN*4*4)=0;
__asm volatile (
"PUSH {r0} \n\t"
"POP {r0} \n\t"
);
}
static void __attribute__ ((noinline)) i2c_write_buff(const uint8_t* buff, uint32_t num) {
uint32_t input=0;
uint32_t output=1;
uint32_t sda=(PERIPH_BB_BASE+((uint32_t)&SDA_PORT->CRL-PERIPH_BASE)*32+SDA_PIN*4*4);
uint32_t scl=(PERIPH_BB_BASE+((uint32_t)&SCL_PORT->CRL-PERIPH_BASE)*32+SCL_PIN*4*4);
__asm volatile (
"LDRB r2,[%[buff]],1 \n\t"
"MVNS r2,r2 \n\t"
"LSLS r2,24 \n\t"
"RBIT r2,r2 \n\t"
"MOVS r3,8 \n\t"
"NOP \n\t"
"NOP \n\t"
"B first_bit \n\t"
"next_bit: \n\t"
"NOP \n\t"
"STR %[input],[%[scl]] \n\t"
"PUSH {r0} \n\t"
"POP {r0} \n\t"
"NOP \n\t"
"first_bit: \n\t"
"STR %[output],[%[scl]] \n\t"
"STR r2,[%[sda]] \n\t"
"LSRS r2,#1 \n\t"
"SUBS r3,#1 \n\t"
"BNE next_bit \n\t"
"LDRB r2,[%[buff]],1 \n\t"
"MVNS r2,r2 \n\t"
"STR %[input],[%[scl]] \n\t"
"LSLS r2,24 \n\t"
"RBIT r2,r2 \n\t"
"MOVS r3,8 \n\t"
"NOP \n\t"
"STR %[output],[%[scl]] \n\t"
"STR %[input],[%[sda]] \n\t"
"STR %[input],[%[scl]] \n\t"
"PUSH {r0} \n\t"
"POP {r0} \n\t"
"SUBS %[num],#1 \n\t"
"BNE first_bit \n\t"
"STR %[output],[%[scl]] \n\t"
:
:[buff] "r" (buff),[num] "r" (num), [input] "r" (input), [output] "r" (output),[sda] "r" (sda), [scl] "r" (scl),
[sdar] "X" (((uint32_t)&SDA_PORT->IDR-PERIPH_BASE)*32+SDA_PIN*4-(((uint32_t)&SDA_PORT->CRL-PERIPH_BASE)*32+SDA_PIN*4*4)),
[sclr] "X" (((uint32_t)&SCL_PORT->IDR-PERIPH_BASE)*32+SCL_PIN*4-(((uint32_t)&SCL_PORT->CRL-PERIPH_BASE)*32+SCL_PIN*4*4))
:"r2","r3"
);
}
int __main (void){
i2c_init();
i2c_start();
i2c_write_buff(init_bytes, sizeof(init_bytes));
i2c_stop();
i2c_start();
i2c_write_buff(test, sizeof(test));
do {
i2c_write_buff(test+2, sizeof(test)-2);
}
while (1);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
i2c_stop();
__asm volatile ("BKPT");
return 0;
#pragma clang diagnostic pop
}
void __attribute__ ((naked)) __reset(void){
__asm volatile(
"POP {r1-r6,r8,r9,r10} \n\t"
"MOV sp,r1 \n\t"
"MOVS r1,1 \n\t"
"STR r1,[r2,%0] \n\t" //HSE On
"STR r1,[r3] \n\t" //FLASH LATENCY = 2
"wait_HSERDY: \n\t"
"LDR r0,[r2,%1] \n\t"
"MOVS r0,r0 \n\t"
"BEQ wait_HSERDY \n\t"
"STR r5,[r4] \n\t" //PLL MULL = 9
"STR r1,[r2,%2] \n\t" //PLL On
"wait_PLLRDY: \n\t"
"LDR r0,[r2,%3] \n\t"
"MOVS r0,r0 \n\t"
"BEQ wait_PLLRDY \n\t"
"STR r1,[r6] \n\t" //PLL selected as system clock
"wait_PLL: \n\t"
"LDR r0,[r6,%4] \n\t"
"MOVS r0,r0 \n\t"
"BEQ wait_PLL \n\t"
"STR r7,[r2] \n\t" //HSI Off
"STR r9,[r8,4] \n\t"
"STR r10,[r8] \n\t"
"B __main \n\t"
:
: "X" ((RCC_CR_HSEON_Pos-RCC_CR_HSION_Pos)*4),
"X" ((RCC_CR_HSERDY_Pos-RCC_CR_HSION_Pos)*4),
"X" ((RCC_CR_PLLON_Pos-RCC_CR_HSION_Pos)*4),
"X" ((RCC_CR_PLLRDY_Pos-RCC_CR_HSION_Pos)*4),
"X" ((POS(RCC_CFGR_SWS_1)-POS(RCC_CFGR_SW_1))*4)
:
);
}
В строках 4-7 можно прописать “свои” пины для SDA и SCL - при компиляции все константы изменятся под эти пины.
Строки запуска SysTick 206-207 и константы для него строки 22-24 можно удалить.
Я через SysTick смотрел число тактов с учетом wait states …