Fake STM32F103C8T6 / APM32F103CCT6/T7 (64kb ОЗУ / 256kb FLASH), device ID: 0x414

Тогда моргать диодом -
длинная пауза
моргаем десятки
короткая пауза
моргаем единицы

открыть STM32CubeProgrammer в режиме CLI ,подсоедениться к чипу через ST-LInk , найти границу памяти ОЗУ попытакми напряму писать в адреса памяти, до тех пор ,пока не зависнет или вернеться какой то error

ну или перепрошить st-link в j-link и делать то же самое через коммандную строку в J-Flash или J-LinkGDBCLI или типа того

1 лайк

набросал пример

Спойлер
/**
 ******************************************************************************
 * @file           : main.c
 * @author         : Auto-generated by STM32CubeIDE
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

//#include <stdint.h>
#include "stm32f10x.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void) {
	  __IO int StartUpCounter;
	  ////////////////////////////////////////////////////////////
	  //Запускаем кварцевый генератор
	  ////////////////////////////////////////////////////////////
	  RCC->CR |= RCC_CR_HSEON; //Запускаем генератор HSE
	  //Ждем успешного запуска или окончания тайм-аута
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    //Если успешно запустилось, то
	    //выходим из цикла
	    if (RCC->CR & RCC_CR_HSERDY) break;
	    //Если не запустилось, то
	    //отключаем все, что включили
	    //и возвращаем ошибку
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      return 1;
	    }
	  }
	  ////////////////////////////////////////////////////////////
	  //Настраиваем и запускаем PLL
	  ////////////////////////////////////////////////////////////
	  //Настраиваем PLL
	  RCC->CFGR |= RCC_CFGR_PLLMULL_0 | RCC_CFGR_PLLMULL_1 | RCC_CFGR_PLLMULL_2;  //PLL множитель равен 9 // 0111: PLL input clock x 9
	  RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; //Тактирование PLL от HSE
	  RCC->CR |= RCC_CR_PLLON; //Запускаем PLL
	  //Ждем успешного запуска или окончания тайм-аута
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    //Если успешно запустилось, то
	    //выходим из цикла
	    if (RCC->CR & RCC_CR_PLLRDY) break;
	    //Если по каким-то причинам не запустился PLL, то
	    //отключаем все, что включили
	    //и возвращаем ошибку
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      RCC->CR &= ~RCC_CR_PLLON; //Останавливаем PLL
	      return 2;
	    }
	  }
	  ////////////////////////////////////////////////////////////
	  //Настраиваем FLASH и делители
	  ////////////////////////////////////////////////////////////
	  //Устанавливаем 2 цикла ожидания для Flash
	  //так как частота ядра у нас будет 48 MHz < SYSCLK <= 72 MHz
	  FLASH->ACR |= FLASH_ACR_LATENCY_1; // 010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz
	  //Делители
	  RCC->CFGR &= ~RCC_CFGR_PPRE2; //Делитель шины APB2 отключен // 0xx: HCLK not divided
	  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; //Делитель нишы APB1 равен 2 // 100: HCLK divided by 2
	  RCC->CFGR &= ~RCC_CFGR_HPRE; //Делитель AHB отключен // 0xxx: SYSCLK not divided
	  RCC->CFGR &= ~RCC_CFGR_SW; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  RCC->CFGR |= RCC_CFGR_SW_1; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  //Ждем, пока переключимся
	  while(!(RCC->CFGR & RCC_CFGR_SWS_1));
	  //После того, как переключились на
	  //внешний источник такирования
	  //отключаем внутренний RC-генератор
	  //для экономии энергии
	  //RCC->CR &= ~RCC_CR_HSION; // При отключенном HSI Или его частоте выше 24 МГц не работает запись/стирание FLASH пользовательской памяти!!!
	  //Настройка и переклбючение сисемы
	  //на внешний кварцевый генератор
	  //и PLL запершилось успехом.
	  //Выходим
		RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // GPIO port C
		GPIOC->CRH &= ~GPIO_CRH_MODE13; // 00: Input mode (reset state)
		GPIOC->CRH |= GPIO_CRH_MODE13_0; // 01: Output mode, max speed 10 MHz.
		GPIOC->CRH &= ~GPIO_CRH_CNF13; // 00: General purpose output push-pull

		GPIOC->BSRR |= GPIO_BSRR_BS13; // PC13 HIGH LED OFF

		#define magic_byte ((unsigned char)0xC6)
		#define max_sram_adr ((unsigned long)20*1024)
		#define test_ram_adr ((unsigned long)max_sram_adr-4)

		*((unsigned char *)test_ram_adr) = magic_byte;

		if ((*((unsigned char *)test_ram_adr)) == magic_byte) {
			GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW LED ON
		}

		return 0;
}

102 строка не отрабатывает
или запись ниже максимальной границы даже не работает или я что то не так написал :thinking:

так оно в ассемблере выглядит

		if ((*((unsigned char *)test_ram_adr)) == magic_byte) {
 80002b0:	f644 73fc 	movw	r3, #20476	; 0x4ffc
 80002b4:	781b      	ldrb	r3, [r3, #0]
 80002b6:	2bc6      	cmp	r3, #198	; 0xc6
 80002b8:	d105      	bne.n	80002c6 <main+0x156>
			GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW LED ON
 80002ba:	4b08      	ldr	r3, [pc, #32]	; (80002dc <main+0x16c>)
 80002bc:	691b      	ldr	r3, [r3, #16]
 80002be:	4a07      	ldr	r2, [pc, #28]	; (80002dc <main+0x16c>)
 80002c0:	f043 5300 	orr.w	r3, r3, #536870912	; 0x20000000
 80002c4:	6113      	str	r3, [r2, #16]
		}


адрес начала 0х02000000 + test_ram_adr

Вы не туда стучитесь !
0x20005000-4, а не 0x5000-4

да, забыл что не с нуля память идет.

в итоге: ниже макс границы - работает, выше - не работает.

Спойлер
#include "stm32f10x.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void) {
	  __IO int StartUpCounter;
	  RCC->CR |= RCC_CR_HSEON; //Запускаем генератор HSE
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    if (RCC->CR & RCC_CR_HSERDY) break;
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      return 1;
	    }
	  }
	  RCC->CFGR |= RCC_CFGR_PLLMULL_0 | RCC_CFGR_PLLMULL_1 | RCC_CFGR_PLLMULL_2;  //PLL множитель равен 9 // 0111: PLL input clock x 9
	  RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; //Тактирование PLL от HSE
	  RCC->CR |= RCC_CR_PLLON; //Запускаем PLL
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    if (RCC->CR & RCC_CR_PLLRDY) break;
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      RCC->CR &= ~RCC_CR_PLLON; //Останавливаем PLL
	      return 2;
	    }
	  }
	  FLASH->ACR |= FLASH_ACR_LATENCY_1; // 010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz
	  RCC->CFGR &= ~RCC_CFGR_PPRE2; //Делитель шины APB2 отключен // 0xx: HCLK not divided
	  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; //Делитель нишы APB1 равен 2 // 100: HCLK divided by 2
	  RCC->CFGR &= ~RCC_CFGR_HPRE; //Делитель AHB отключен // 0xxx: SYSCLK not divided
	  RCC->CFGR &= ~RCC_CFGR_SW; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  RCC->CFGR |= RCC_CFGR_SW_1; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  while(!(RCC->CFGR & RCC_CFGR_SWS_1));
		RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // GPIO port C
		GPIOC->CRH &= ~GPIO_CRH_MODE13; // 00: Input mode (reset state)
		GPIOC->CRH |= GPIO_CRH_MODE13_0; // 01: Output mode, max speed 10 MHz.
		GPIOC->CRH &= ~GPIO_CRH_CNF13; // 00: General purpose output push-pull

		GPIOC->BSRR |= GPIO_BSRR_BS13; // PC13 HIGH LED OFF

		#define magic_byte ((unsigned char)0xC6)
		#define max_sram_adr ((unsigned long)20*1024+0x20000000)
		#define test_ram_adr ((unsigned long)max_sram_adr-4)

		unsigned char * ptrB = (unsigned char *) test_ram_adr;
		*ptrB = magic_byte;

		if (*ptrB == magic_byte) {
			GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW LED ON
		}

		return 0;
}

Следовательно 20К…
А зачем для того что бы моргнуть диодом разгонять HSE и PLL ?

что соответствует :


из

А с флеш не соответствует …

а этого мы точно не знаем , так как писать везде не пытались

я даже не сомневался :slight_smile:

ну а FLASH проверяется тупо в ST Link Utility

вру, не дает он прыгнцть выше потолка, сейчас попробую программу состряпать

в моем МК 512 страниц флэша по 128 байт
511 ый записался без проблем

Спойлер
#include "stm32f10x.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

#define NVIC_VectTab_FLASH		((unsigned long)0x08000000) // начало флэша
#define FLASH_PAGE_SIZE			((unsigned long)128) // CHF32F103C8T6 -> 128 // размер одной страницы // размер страницы памяти для большинства МК серии STM32F103 составляет 1Kb, за исключением микроконтроллеров линейки HD и CL (Connectivity Line), в которых она равна двум килобайтам
#define NUM_PAGE_EEPROM_BEGIN	((unsigned long)511) // с какой страницы памяти будем писать свои данные // 256*128=0x8000->0x8008000
#define FIRMWARE_PAGE_OFFSET 	((unsigned long)NUM_PAGE_EEPROM_BEGIN*FLASH_PAGE_SIZE) // смещение в байтах, с которого будем писать свои данные

unsigned long FLASH_read(uint32_t address) {
	return (*(__IO uint32_t*) address);
}

#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)

void FLASH_Unlock(void) {
	  FLASH->KEYR = FLASH_KEY1;
	  FLASH->KEYR = FLASH_KEY2;
}

void FLASH_Lock() {
	FLASH->CR |= FLASH_CR_LOCK;
}

void FLASH_ErasePage(unsigned long inAdr) {
	  FLASH->CR |= FLASH_CR_PER; //Устанавливаем бит стирания одной страницы
	  FLASH->AR = inAdr; // Задаем её адрес
	  FLASH->CR |= FLASH_CR_STRT; // Запускаем стирание
	  while ((FLASH->SR & FLASH_SR_BSY) != 0 ); // Wait end of eraze
	  FLASH->CR &= ~FLASH_CR_PER; //Сбрасываем бит обратно
}

void FLASH_fill_page(uint32_t Value) {
	uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET;                    // Адрес страницы памяти
	FLASH_Unlock();                                                         // Разблокируем память для записи
	FLASH_ErasePage(pageAdr);                                               // Очистим страницу памяти
	FLASH->CR |= FLASH_CR_PG; //Разрешаем программирование флеша
	for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) {
		unsigned long inValue = Value;
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  *(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем младшие 2 бата
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  pageAdr += 2;
		  inValue>>=16;
		  *(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем старшие 2 байта
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  pageAdr += 2;
	}
	FLASH->CR &= ~FLASH_CR_PG; //Запрещаем программирование флеша
	FLASH_Lock();
}

void FLASH_write_param(unsigned short numParam, uint32_t paramValue) {
	uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET; // Адрес страницы памяти
	numParam %= FLASH_PAGE_SIZE/4; // номер параметра не может превысить число 4х байтовых слов в странице
	unsigned long dataPage[FLASH_PAGE_SIZE/4]; // место куда сохраним текущую страницу
	for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) dataPage[i] = FLASH_read(pageAdr + i * 4);
	dataPage[numParam] = paramValue;
	FLASH_Unlock();                                                         // Разблокируем память для записи
	FLASH_ErasePage(pageAdr);                                               // Очистим страницу памяти
	FLASH->CR |= FLASH_CR_PG; //Разрешаем программирование флеша
	for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) {
		unsigned long inValue = dataPage[i];
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  *(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем младшие 2 бата
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  pageAdr += 2;
		  inValue>>=16;
		  *(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем старшие 2 байта
		  while ((FLASH->SR & FLASH_SR_BSY) != 0 );
		  pageAdr += 2;
	}
	FLASH->CR &= ~FLASH_CR_PG; //Запрещаем программирование флеша
	FLASH_Lock();
}

unsigned long FLASH_read_param(unsigned short numParam) {
	uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET; // Адрес страницы памяти
	numParam %= FLASH_PAGE_SIZE/4; // номер параметра не может превысить число 4х байтовых слов в странице
	return FLASH_read(pageAdr + numParam * 4);
}

int main(void) {
	  __IO int StartUpCounter;
	  RCC->CR |= RCC_CR_HSEON; //Запускаем генератор HSE
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    if (RCC->CR & RCC_CR_HSERDY) break;
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      return 1;
	    }
	  }
	  RCC->CFGR |= RCC_CFGR_PLLMULL_0 | RCC_CFGR_PLLMULL_1 | RCC_CFGR_PLLMULL_2;  //PLL множитель равен 9 // 0111: PLL input clock x 9
	  RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; //Тактирование PLL от HSE
	  RCC->CR |= RCC_CR_PLLON; //Запускаем PLL
	  for(StartUpCounter=0; ; StartUpCounter++) {
	    if (RCC->CR & RCC_CR_PLLRDY) break;
	    if (StartUpCounter > 0x1000) {
	      RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
	      RCC->CR &= ~RCC_CR_PLLON; //Останавливаем PLL
	      return 2;
	    }
	  }
	  FLASH->ACR |= FLASH_ACR_LATENCY_1; // 010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz
	  RCC->CFGR &= ~RCC_CFGR_PPRE2; //Делитель шины APB2 отключен // 0xx: HCLK not divided
	  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; //Делитель нишы APB1 равен 2 // 100: HCLK divided by 2
	  RCC->CFGR &= ~RCC_CFGR_HPRE; //Делитель AHB отключен // 0xxx: SYSCLK not divided
	  RCC->CFGR &= ~RCC_CFGR_SW; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  RCC->CFGR |= RCC_CFGR_SW_1; //Переключаемся на работу от PLL // 10: PLL selected as system clock
	  while(!(RCC->CFGR & RCC_CFGR_SWS_1));
		RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // GPIO port C
		GPIOC->CRH &= ~GPIO_CRH_MODE13; // 00: Input mode (reset state)
		GPIOC->CRH |= GPIO_CRH_MODE13_0; // 01: Output mode, max speed 10 MHz.
		GPIOC->CRH &= ~GPIO_CRH_CNF13; // 00: General purpose output push-pull

		GPIOC->BSRR |= GPIO_BSRR_BS13; // PC13 HIGH LED OFF

		/*#define magic_byte ((unsigned char)0xC6)
		#define max_sram_adr ((unsigned long)20*1024+0x20000000)
		#define test_ram_adr ((unsigned long)max_sram_adr-4)
		unsigned char * ptrB = (unsigned char *) test_ram_adr;
		*ptrB = magic_byte;
		if (*ptrB == magic_byte) {
			GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW LED ON
		}*/

		FLASH_write_param(8, 0x12345678);
		unsigned long testParam = FLASH_read_param(8);
		testParam += 0x20;
		FLASH_write_param(11, testParam);

		GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW LED ON

		return 0;
}

сейчас попробую 512ый записать и проверить результат

нет, китайцы лишнего не доложили :slightly_smiling_face:
МК наглухо завис.

А зачем?
Что, Си не позволяет записать в указатель произвольное число, а потом попытаться осуществить чтение/запись по этому указателю?

это делал чтоб стэк сдвинуть на верхную границу памяти (как оказалось несуществующей)

Кстати, очень удивлен - в чем смысл? Мои “синие таблетки” дешевле твоих чуть-ли не в 1,5 раза, а ресурсов больше наклали )))

смысл что не доложили? :slight_smile:
или что? не понял вопроса.
вам же было любопытно лишнюю память помотреть, мне оно не надо :slight_smile:
просто оттестировали механизм проверки…

Лень обрезать готовую функцию инициализации.