Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 >> STR R1, [R0] >> сохраняется не корректно
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Tahoe
Буэнос утрас, амигас! sm.gif


STM32F103RC + IAR 6.30 + J-LINK

Использую SPI1, через пины PB3, PB4 и PB5. Основная функция PB3, это JTDO. А основная функция PB4, это NJTRST. Обе мне не нужны, поскольку работаю через Serial Wire. Что бы вывести на эти ноги сигналы SPI1, конфигурирую их как альтернативные и делаю remap:
Код
    McuPinInit(    BSP_PIN_ISM_CSn,    MCU_PIN_MODE_OUT_GP_PP_10MHZ );
    McuPinInit(    BSP_PIN_ISM_SCK,    MCU_PIN_MODE_OUT_AF_PP_10MHZ );
    McuPinInit(    BSP_PIN_ISM_SI,        MCU_PIN_MODE_OUT_AF_PP_10MHZ );
    McuPinInit(    BSP_PIN_ISM_SO,        MCU_PIN_MODE_OUT_AF_PP_10MHZ );
    McuPinInit(    BSP_PIN_ISM_GDO2,    MCU_PIN_MODE_INP_FLOATING );
    McuPinInit(    BSP_PIN_ISM_GDO0,    MCU_PIN_MODE_INP_FLOATING );

    McuPioRemap( MCU_PIO_REMAP_SPI1_ENABLE );
    //McuPioRemap( MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_EN );
    McuPioRemap( MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST );

По конфигурации проблем нет, клок на GPIOx и AFIO включается в McuPinInit().

А вот с remap творится чертовщина. Ниже текст текущего варианта McuPioRemap(). Лишнее покоцал, но суть и так понятна:
CODE
typedef enum MCU_PIO_REMAP_e
{
MCU_PIO_REMAP_SWJ_CFG_FULL,
MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST,
MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_EN,
MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_DIS,
...
MCU_PIO_REMAP_I2C1_DISABLE,
MCU_PIO_REMAP_I2C1_ENABLE,
MCU_PIO_REMAP_SPI1_DISABLE,
MCU_PIO_REMAP_SPI1_ENABLE
} MCU_PIO_REMAP;


////////////////////////////////////////////////////////////////////////////////
void McuPioRemap( MCU_PIO_REMAP Remap )
{
switch( Remap )
{
case MCU_PIO_REMAP_SWJ_CFG_FULL:
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_0;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_1;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_2;
break;

case MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST:
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_0;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_1;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_2;
break;

case MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_EN:
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_0;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_1;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_2;
break;

case MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_DIS:
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_0;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_1;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_2;
break;

...

case MCU_PIO_REMAP_I2C1_DISABLE:
AFIO->MAPR &= ~AFIO_MAPR_I2C1_REMAP;
break;

case MCU_PIO_REMAP_I2C1_ENABLE:
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
break;

case MCU_PIO_REMAP_SPI1_DISABLE:
AFIO->MAPR &= ~AFIO_MAPR_SPI1_REMAP;
break;

case MCU_PIO_REMAP_SPI1_ENABLE:
AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP;
break;

default:
break;
}
}


Сначала у меня перестал откликаться SW, пришлось временно закомментить remap. Подумал, что либо сам ошибся, либо в <stm32f10x.h> косячёк в #define. Полез смотреть по шагам. Вижу вполне корректный ассемблер:
Код
            AFIO->MAPR    |=    AFIO_MAPR_SWJ_CFG_0;
??McuPioRemap_4:
    0x8000d40: 0xf8df 0x03f8  LDR.W     R0, ??DataTable4_6; AFIO_MAPR
    0x8000d44: 0x6801         LDR       R1, [R0]
    0x8000d46: 0xf041 0x7180  ORR.W     R1, R1, #16777216; 0x1000000
    0x8000d4a: 0x6001         STR       R1, [R0]
            AFIO->MAPR    &=    ~AFIO_MAPR_SWJ_CFG_1;
    0x8000d4c: 0x6801         LDR       R1, [R0]
    0x8000d4e: 0xf021 0x7100  BIC.W     R1, R1, #33554432; 0x2000000
    0x8000d52: 0x6001         STR       R1, [R0]
            AFIO->MAPR    &=    ~AFIO_MAPR_SWJ_CFG_2;
    0x8000d54: 0x6801         LDR       R1, [R0]
    0x8000d56: 0xf021 0x6180  BIC.W     R1, R1, #67108864; 0x4000000
    0x8000d5a: 0xe127         B.N       ??McuPioRemap_3; 0x8000fac

    ...

??McuPioRemap_3:
    0x8000fac: 0x6001         STR       R1, [R0]
}


Когда дохожу до строки
0x8000d4a: 0x6001 STR R1, [R0]
в регистрах вижу корректные значения, в R1 значение 0x01000001, а в R0 адрес AFIO->MAPR ( 0x40010004 ).
Сразу после исполнения STR R1, [R0] в AFIO->MAPR вижу уже 0x02000001, вместо 0x01000001. Ну и на следующей инструкции, конечно, считывается как 0x02000001. Ну как-же так, доктор? Причем каждый из трех бит SWJ_CFG так же аккуратно сдвигается на единицу влево. А вот младшая 1, это remap SPI1, который был сделан ранее, причем этой же функцией. И ведь все корректно!

Нажмите для просмотра прикрепленного файла

P.S.
В еррате ничего похожего не нашел.
Tahoe
Пара дополнений.

1. Согласно даташит, значения из SWJ_CFG не считываются корректно:
Цитата
Bits 26:24 SWJ_CFG[2:0]: Serial wire JTAG configuration
These bits are write-only (when read, the value is undefined). They are used to configure the SWJ and trace alternate function I/Os. The SWJ (Serial Wire JTAG) supports JTAG or SWD access to the Cortex debug port. The default state after reset is SWJ ON without trace. This allows JTAG or SW mode to be enabled by sending a specific sequence on the JTMS / JTCK pin.

000: Full SWJ (JTAG-DP + SW-DP): Reset State
001: Full SWJ (JTAG-DP + SW-DP) but without NJTRST
010: JTAG-DP Disabled and SW-DP Enabled
100: JTAG-DP Disabled and SW-DP Disabled
Other combinations: no effect


Но я сужу об их поведении по внешнему проявлению - у меня при записи комбинации бит 010 сразу отключается SW и, как следствие, отваливается отладчик. Т.е. ведет себя так, как если бы была записана комбинация 100.


2. Если поменять местами вызовы функций, т.е. сделать вот так:
McuPioRemap( MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST );
McuPioRemap( MCU_PIO_REMAP_SPI1_ENABLE );

то все чудесным образом начинает работать. И SPI пероиферию инициализирует, и отладчик не отваливается... cranky.gif
scifi
Вы уже сами написали, что работа с AFIO_MAPR у вас ведётся некорректно. Какой смысл разбираться дальше? Делайте как положено: AFIO_MAPR = (AFIO_MAPR & 0xF8FFFFFF) | new_val.
Tahoe
Посмотрел сейчас стандартную библиотеку от ST, функцию GPIO_PinRemapConfig(). Забавная картина получается. Из-за того, что биты SWJ_CFG не доступны для чтения, нет возможности узнать их текущее состояние. А это значит, что если сначала сделать remap в SWJ_CFG, а затем попытаться сделать remap для любой другой периферии, висящей на этом же регистре, то нет возможности узнать ( а значит и восстановить в процессе read-modify-write операции ) их текущее состояние. Заодно стали понятны причины всех этих плясок с бубнами в стандартной библиотеке, с DBGAFR_SWJCFG_MASK и прочим.

Вывод: любые remaps периферии нужно делать до remap JTAG-пинов. Т.е. биты SWJ_CFG должны быть записаны самыми последними.
scifi
Цитата(Tahoe @ Jul 20 2012, 11:08) *
Посмотрел сейчас стандартную библиотеку от ST, функцию GPIO_PinRemapConfig().

Только не берите пример с этой библиотеки. Качество кода там оставляет желать лучшего, мягко говоря. Первоисточник - это Reference Manual.
Tahoe
Цитата(scifi @ Jul 20 2012, 10:55) *
Вы уже сами написали, что работа с AFIO_MAPR у вас ведётся некорректно. Какой смысл разбираться дальше? Делайте как положено: AFIO_MAPR = (AFIO_MAPR & 0xF8FFFFFF) | new_val.

Угу. Хотя это не лучший выход.

Правда маска в стандартной библиотеке 0xF0FFFFFF, а не 0xF8FFFFFF, как в доке. Думаю, что не случайно, особенно в свете поведения AFIO_MAPR при записи ( я про сдвиг на один бит влево в группе SWJ_CFG ).

Цитата(scifi @ Jul 20 2012, 11:12) *
Только не берите пример с этой библиотеки. Качество кода там оставляет желать лучшего, мягко говоря. Первоисточник - это Reference Manual.

Конечно. Потому и приходится, к сожалению, изобретать велосипед - писать своё. По мере надобности дописываю нужные куски.
scifi
Цитата(Tahoe @ Jul 20 2012, 11:18) *
Правда маска в стандартной библиотеке 0xF0FFFFFF, а не 0xF8FFFFFF, как в доке. Думаю, что не случайно, особенно в свете поведения AFIO_MAPR при записи ( я про сдвиг на один бит влево в группе SWJ_CFG ).

Маска как раз вполне случайная. Можно было бы даже взять 0x00FFFFFF: очевидно, что разницы не будет.
Вот что я имел в виду, когда советовал не засматриваться на код этой библиотеки: можете заразиться совершенно неверными идеями. Первоисточник - Reference Manual, остальное - от лукавого.
Tahoe
Цитата(scifi @ Jul 20 2012, 11:22) *
Первоисточник - Reference Manual, остальное - от лукавого.

В целом - да. Но в данном случае, судя по всему, не корректен имено Reference Manual. Вот это:
Цитата
000: Full SWJ (JTAG-DP + SW-DP): Reset State

не соотвествует действительности.

Как я писал ранее:
Цитата
2. Если поменять местами вызовы функций, т.е. сделать вот так:
McuPioRemap( MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST );
McuPioRemap( MCU_PIO_REMAP_SPI1_ENABLE );

то все чудесным образом начинает работать. И SPI пероиферию инициализирует, и отладчик не отваливается...


Т.е. сначала я отключаю JTAG, а потом ( если верить мануалу ), записывая 0x00000001, тем самым записываю и 000 в SWJ_CFG. А стало быть, снова включаю JTAG, то бишь отключаю SPI1. Однако ж SPI1 остается "живее всех живых"(с), потому что продлолжает спокойно работать с периферией.

И еще, насчет мануала. Ничего не имею против поведения NSS в SPI, как его организовали ST. Сначала огорчился, но потом пришел к выводу, что ничего фатального в этом нет: для single операций скорость все равно не критична, а для DMA, как правило, все равно приходится использовать прерывание об окончании трансфера, так что одно обращение к пину в нем особо погоды не делает.
Но мало того, что они криво описали поведение NSS ( написанное в мануале расходилось с реальным поведенпием пина ), так ещё и не хотели сознаваться, что у них свой, особенный взгляд на NSS в SPI.
scifi
Цитата(Tahoe @ Jul 20 2012, 11:43) *
не соотвествует действительности.

Не верю.

Цитата(Tahoe @ Jul 20 2012, 11:43) *
Т.е. сначала я отключаю JTAG, а потом ( если верить мануалу ), записывая 0x00000001, тем самым записываю и 000 в SWJ_CFG.

Это вы так думаете. В связи с тем, что работа с регистром у вас сделана некорректно, на самом деле может происходить что-то совсем иное. Дальше разбираться лень, да и пользы от этого не будет.
Tahoe
Цитата(scifi @ Jul 20 2012, 11:47) *
В связи с тем, что работа с регистром у вас сделана некорректно

Да что ж тут может быть не корректного? sm.gif По сути, речь про одну строчку:
Код
AFIO->MAPR        =    0x00000001;



CODE
////////////////////////////////////////////////////////////////////////////////
void McuPioRemap( MCU_PIO_REMAP Remap )
{
uint32_t Temp = AFIO->MAPR & 0xF0FFFFFF;


switch( Remap )
{
case MCU_PIO_REMAP_SWJ_CFG_FULL:
Temp &= ~AFIO_MAPR_SWJ_CFG;
break;

case MCU_PIO_REMAP_SWJ_CFG_FULL_WITHOUT_NJTRST:
Temp &= ~AFIO_MAPR_SWJ_CFG;
Temp |= AFIO_MAPR_SWJ_CFG_0;
break;

case MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_EN:
Temp &= ~AFIO_MAPR_SWJ_CFG;
Temp |= AFIO_MAPR_SWJ_CFG_1;
break;

case MCU_PIO_REMAP_SWJ_CFG_JTAG_DIS_SW_DIS:
Temp &= ~AFIO_MAPR_SWJ_CFG;
Temp |= AFIO_MAPR_SWJ_CFG_2;
break;
...

case MCU_PIO_REMAP_I2C1_DISABLE:
Temp &= ~AFIO_MAPR_I2C1_REMAP;
break;

case MCU_PIO_REMAP_I2C1_ENABLE:
Temp |= AFIO_MAPR_I2C1_REMAP;
break;

case MCU_PIO_REMAP_SPI1_DISABLE:
Temp &= ~AFIO_MAPR_SPI1_REMAP;
break;

case MCU_PIO_REMAP_SPI1_ENABLE:
Temp |= AFIO_MAPR_SPI1_REMAP;
break;

default:
break;
}

AFIO->MAPR = Temp;
}


Хотя неоднозначность заложена в самом мануале. Он должен описать поведение PB3, PB4, которые используются и JTAG, и SPI. При этом значение 0x00000001 для MAPR допустимо. Оно одновременно должно включать как SPI1 remap, так и JTAG-DP. Учитывая, что в том же мануале, основная функция PB3 это как раз JTDO, да и приоритеты явно не указаны, логично ожидать, что PB3 не будет функционировать как SPI1_SCK, а будет исполнять свою основную функцию JTDO.

Ладно, забудем. sm.gif

Сейчас проверил окончательный вариант. Пока не передернул питание, состояние SWJ_CFG не менялось. А вот когда питание передернул, доступ к периферии уже отсутствовал.

В общем вывод остается прежним - remap JTAG делать в самую последнюю очередь.
А в библиотеках от ST просто в наглую подставляется константа. И совсем не факт, что она совпадет с тем, как ранее настроил программер.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.