First of all, you see it being called exactly 10 times because that's the limit ammount of $digest cycles that can be run before angular throws an exception.
That usually happens when you change object properties during the render process. This would trigger a new render and therefore a loop wich will cause the "10 $digest() iterations reached. Aborting!" error. (a.k.a Infinite $digest loop)
You can solve this changing your code to this:
<div ng-controller="HelloCtrl">
Say hello to: <input type="text" ng-model="name" ng-change="i()"/><br/>
<h1>Characters typed, {{keysTyped}}!</h1>
</div>
and on your controller:
$scope.keysTyped = 0;
$scope.i = function () {
$scope.keysTyped++;
};
What I've done was simply making use of Angular's two-way binding to solve the problem.
I've took your code and modified it just to make it work and explain why you're getting an Infinite $digest loop.
If all you want is to have a count of characters in the input field, all you need to do is this:
<body ng-app="">
<div ng-controller="HelloCtrl">
Say hello to: <input type="text" ng-model="name"/><br/>
<h1>Characters typed, {{name.length || 0}}!</h1>
</div>
</body>
You don't need a function to count the characters.