Comment initialiser I2C sur STM32F0?
Récemment, j'ai essayé d'obtenir le bus I2C de travail sur la STM32F030F4P6 MCU, mais avec un peu de chance.
Je suis en utilisant un STM32F0 module et ont trouvé une foule de ressources pour la STM32F1 module I2C l'initialisation, mais rien de précis sur l'STM32F0 initialisation/processus de transfert.
Voici mon code d'initialisation:
void i2c_init(uint8_t ownAddress)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
//Enable GPIOA clocks
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
//Configure I2C1 clock and GPIO
GPIO_StructInit(&GPIO_InitStructure);
/* I2C1 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* I2C1 SDA and SCL configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* I2C1 Reset */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
/* Configure I2C1 */
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_StructInit(&I2C_InitStructure);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
//I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = ownAddress;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
//I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
Afin de tester pour voir si mon installation est correcte, j'ai conçu quelques I2C transmission d'un code de transfert de données dans une boucle sans fin. Voici le code pour que:
while(1)
{
I2C_SlaveAddressConfig(I2C1, RegName);
I2C_GenerateSTART(I2C1, ENABLE);
I2C_NumberOfBytesConfig(I2C1, 8);
I2C_SendData(I2C1,0b00000000);
I2C_GenerateSTOP(I2C1, ENABLE);
}
Où:
RegName = 0x75
SDA = GPIO_PIN_10 sur GPIOA
SCL = GPIO_PIN_9 sur GPIOA
I2C = I2C1
ownAdrress = 0x68
Quand je l'ai portée I2C lignes après que j'ai commencer ce code j'obtiens une tension flottante autour de 160mV. Quand je marche à travers le code de chacun des I2C appels de fonction arriver et complète, c'est pourquoi je pensais qu'il avait quelque chose de plus à faire avec mon initialisation des pins eux-mêmes.
Mon problème est très similaire à ce fil, mais n'a jamais été répondu:
Edit 1: Voici mon code plus tard; ne fonctionne toujours pas (Edit 2: mise à Jour de ce que j'ai actuellement; déplacé les choses en plus d'emplacements corrects):
void i2c_init(uint8_t ownAddress)
{
/* TypeDefs for GPIOA and I2C1 */
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* Enable GPIOA clocks and I2C1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* Configure I2C1 clock and GPIO */
GPIO_StructInit(&GPIO_InitStructure);
/* I2C1 SDA and SCL configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //UP
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
/* GPIO AF Configuration -> GPIO_AF_1: USART2, CEC, Tim3, USART1, USART2,EVENTOUT, I2C1, I2C2, TIM15 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* I2C1 Reset */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
//I2C_DeInit(I2C1);
/* Configure I2C1 */
I2C_StructInit(&I2C_InitStructure);
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = ownAddress;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
//I2C_AcknowledgeConfig(I2C1, ENABLE);
}
Comme vous pouvez le voir, j'ai ajouté les deux lignes GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
et GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
où j'ai trouvé que GPIO_AF_1 avait la fonction de remplacement de I2C1 de le STM32F0 Standard Périphérique bibliotheek.
D'autres idées? J'ai été jouer avec les horloges pour voir si cela a changé quelque chose et ont été l'ajout d'extraits d'autres personnes de code juste pour voir si cela a un effet sur la sortie de mon appareil.
Edit 3: j'ai essayé de tirer à la fois le SDA et SCL lignes jusqu'à VCC avec une résistance d ' 1 kohm selon les instructions de ce guide: https://electronics.stackexchange.com/questions/57121/i2c-pullup-resistor-calculations
->(3.3 V-0.4)/3mA ~= d ' 1 kohm
Edit 4: Après être passé par mon code, ligne par ligne, j'ai essayé de la sortie de divers bit indicateur de registres. Ces registres: isr = I2C1->ISR;
, cr1 = I2C1->CR1;
, et cr2 = I2C1->CR2;
Le drapeau-je obtenir après le début de la I2C transfert de manutention avec I2C_TransferHandling(I2C1, 0x02, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);
était 0x8001
qui peut être déchiffré à deux erreurs:
#define I2C_ISR_BUSY ((uint32_t)0x00008000) /*!< Bus busy */
et
#define I2C_ISR_TXE ((uint32_t)0x00000001) /*!< Transmit data register empty */
J'ai trouvé des solutions à ce lien ici (enlever l'espace après https: pour aller sur le lien -> débordement de pile ne me permet pas de poster plus d'1 lien pour une certaine raison): https: //my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FSTM32L151RB%20I2C%20Busy%20flag%20always%20set&FolderCTID=0x01200200770978C69A1141439FE559eb459d7580009c4e14902c3cde46a77f0ffd06506f5b¤tviews= 690 que je suis à la recherche à mettre en œuvre et de faire rapport dès que j'ai les essayer.
- Probablement une question stupide. Avez-vous des pullups sur SDA et SDL? Sont-ils élevés avant d'exécuter ce code?
- Hé, il n'y DoxyLover, essayé et n'ont pas de travail. Ne croyez pas qu'ils sont élevés avant j'ai couru ce code.
- Qu'avez-vous exactement connecté à l'I2C lignes? Qu'est-ce que l'appareil esclave? Êtes-vous conscient que vous devez avoir des résistances de pull-up sont connectés entre chaque ligne I2C et Vcc?
- Donc, pour l'instant je ne l'ai pas connecté à un autre appareil; c'est tout simplement un maître avec une traction séparé pour chacune des lignes SCL et SDA. Et oui, je suis conscient que je vais finir par avoir besoin d'un pullup pour chaque appareil, je l'ai connecté à. Maintenant je n'ai même pas un signal de démarrage de sortir (je devrais être en mesure de voir les données brutes comme est avec mon code actuel, ou au moins le signal de départ).
- En fait, non, vous n'avez pas besoin de séparer le pull-ups pour chaque appareil. Juste un chacun pour SCL et SDA. Le fait que ces lignes sont bas avant de démarrer l'initialisation de l'I2C peut être un indice important. Le mode par défaut de ces pins semble être dictée (sortie) bas où j'avais l'habitude de drain ouvert (et donc, tiré de haut par les résistances). Malheureusement, j'ai un pas familier avec la série STM32 de la série donc je ne peux vraiment pas vous aider davantage.
- Ouais, ça doit être quelque chose de très spécifique à la série STM32, plus précisément le STM32F0 de la série. Merci pour votre aide bien, je vais continuer et voir si je peux pas trouver une solution à mon propre compte.
- Il vous manque des
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_Pin_9); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_Pin_10);
. Je ne sais pas si c'est important, mais vous pourriez avoir besoin de le faire avant appelerGPIO_Init
. - Ajouté ces lignes de code; voir mon édité réponse ci-dessus pour une mise à jour sur la situation.
Vous devez vous connecter pour publier un commentaire.
J'ai I2C de travail en tant que maître et de l'esclave sur la F0. Le principal problème que je peux voir avec ton code, c'est qu'en mode master, vous devez absolument définir la
I2C_Timing
initialisation de membre de structure. Voir RM0091 pour l'échantillon des valeurs qui correspondent à la fréquence que vous souhaitez générer sur SCL. En mode esclave de l'horloge est récupéré à partir de le maître le moment membre ne semble pas être utilisés.Comme les autres l'ont dit, externe pullups à Vcc sur SCL et SDA ne sont pas facultatifs et doivent être présents une fois par bus pas par périphérique que vous avez mal indiqué dans un commentaire. Vous étiez en droit d'utiliser la calculatrice pour choisir des valeurs parce que l'interne pullups dans le STM32 à environ 30-50K sont beaucoup trop faible pour l'utilisation que l'I2C pullups.
I2C_InitStructure.I2C_Timing = 0x50330309;//400kHz
Cependant, je suis encore en train de rien à la fois sur les lignes SCL et SDA. Je n'ai qu'un appareil maître dès maintenant avec le pullups sur elle, mais je vais garder à l'esprit que je n'ai besoin que d'un pullup par bus pour référence future.Le problème est que vous ne configurez pas bon AF (Fonction de remplacement) source pour les broches I2C. Après la réinitialisation des registres de configuration AF sont tous à 0, et I2C de la fonction est 1, de sorte que votre périphérique I2C est en fait déconnecté de la GPIOs.
Techniquement, il ne fait aucune différence lorsque vous configurez, mais il est préférable de le faire avant GPIO de configuration afin de minimiser les transitions sur les broches.
Modifier: Vous DEVEZ avoir le pullups sur les broches I2C - sans eux, vous avez "faible" niveau là, et I2C périphérique détecte que comme erreur de bus, qui, de toute évidence, il l'empêche de fonctionner correctement. Se connecter à l'résistances externes, ou à tout le moins permettre interne pullups au lieu de "pas de pullups/pas de listes déroulantes" configuration.
D'ailleurs - c'est juste pas possible pour un "drain ouvert" pin pour fonctionner correctement sans pullup.
Le Noyau du Cortex M0 est différente, alors la Base de Cortex M3, STM32f030f4 a AHB et APB1 (ponté) seulement. Le code C de STM32f1xx jamais être exécuté en vertu de STM32f0xx.
Utilisation STM32F0xx_Snippets_Package pour résoudre vos problèmes clés.
Je viens de remarquer cela aussi:
Si vous avez désactivé l'horloge après que vous l'avez activée. Je ne vois pas où vous avez activé de nouveau plus tard.
Je remarque que vous êtes de cartographie les broches à
AF_1
et c'est pour leUART
fonction.Vous avez besoin de la carte à
AF_4
d'utiliser leI2C
fonction.